0
点赞
收藏
分享

微信扫一扫

(c语言实现)算法笔记之bfs及pta习题

朱小落 2022-04-01 阅读 110

目录

一,bfs(广度优先搜索)的定义

二,bfs(广度优先搜索)的应用

三,题型训练

1,奇怪的电梯

2,寻宝 

3,龙舌兰酒吧 

四,总结 



       

一,bfs(广度优先搜索)的定义

 说点人话环节(doge):比如走迷宫,我们一开始肯定会有一个起始位置,而之后改如何走是不太确定的,因为有四个方向可以走,广搜就是,一次搜索就走这四个方向,搜过的点就标记一下,下次不要再回去找(所以这里会标记起始的点,而由起始点走出的四个点还没有搜索,所以不必标记)。之后再从走出的四个点分别进行搜索接下去的四个方向的点。由一次搜索走出来的所有点就是一层。在每次走完一层之后,就先判定一下这一层的点有没有所需要的答案,如果有,那么就不需要再找了。

在图上就是,以V1为起点,第一次搜索就搜V2,V3,并将V1标记。此为一层,这时,应该先判断一下V2,V3是不是我们所需要的点,如果不是,那么就继续,往下搜索V4,V5,V6,V7. 直到找到目标。

那这时候就有人要问了:那找不到怎么办?也有走不通的迷宫啊!

回答这个问题之前,我们要先想想,bfs搜索的时候,数据要放到哪里?我们想想,每一次搜索的时候是不是就是先将要搜索的点放入储存的结构中,然后搜索完标记并退出。这符合“先进先出”的特点,也就是队列的特点。由于只会c语言我们只能去模拟队列的实现。如何模拟呢?用一个数组和两个指针变量就可以了。

就可以模拟队列的实现,当然,如果要使用模拟循环队列也是可以的。(记得加个判断,end>数组长度时,重置即可)但是要主要开好足够的空间 ,不然可能还没搜索,那一层的部分数据就会被覆盖掉。

因为一层一层搜索,所以如果还能走,必然有数据入队,自然就不会出现head>=end的情况(如果是循环队列,那么判断条件应该是head!=end,即head不会与end相等)。一旦出现上述情况,那么就说明没得搜了,已经都走遍了,如果此时还没找到答案,那么就是没有答案了。

二,bfs(广度优先搜索)的应用

目前我所遇到的基本上bfs的应用在于寻找最短路径类,之后如果有遇到其他的应用,会再写一篇文章来描述新的应用。

那么这里就以走迷宫为例,看看如何实现吧。

首先肯定要创建好结构体记录每次走的点,并创建好队列

 然后创建走的四个方向

之后就是主体部分的实现了

三,题型训练

1,奇怪的电梯

这道题也是典型bfs的题目,具体的实现即解释也在代码中

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int judge(int arr[])
{
    int i=0;
    for(i=0;i<2000;i++)
    {
        if(arr[i]!=0)
            return 1;
    }
    return 0;
}
int main()
{
    int n;
    scanf("%d",&n);
    int arr[n+1];
    int i=0;
    int sta,end;
    scanf("%d%d",&sta,&end);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&arr[i]);
    }
    arr[0]=0;
    int queque[2000];//模拟队列的实现
    memset(queque,0,sizeof(queque));
    int top=0,bottom=1;
    queque[top]=sta;
    int count=0;
    int flag=0;
    while(judge(queque))
    {
        //广搜对一层的搜索
        int tmp=bottom;
        while(top<tmp)
        {
           //此处节点标记采用arr[i]=0方式
            if(arr[queque[top]]!=0)
            {
               if(queque[top]+arr[queque[top]]<=n)
               {
                //对上楼层节点进行访问,将可访问节点放入队列并标记该节点
                queque[bottom++]=queque[top]+arr[queque[top]];
                //arr[queque[top]+arr[queque[top]]]=0;
               }
               if(queque[top]-arr[queque[top]]>0)
               {
                //对下楼层进行访问,将可访问节点放入队列并标记该节点
                queque[bottom++]=queque[top]-arr[queque[top]];
               }
                arr[queque[top]]=0;
            }
            top++;
        }
        //搜索一次就需要按一次电梯
        count++;
        //判断目前的层数中有无目标数
        int i=0;
        for(;i<top;i++)
        {
            if(queque[i]==end)
            {
                flag=1;
                 goto ending;
            }
            queque[i]=0;
        }
    }
    ending:
    if(flag)
    printf("%d",count-1);
    else
    printf("-1");
    return 0;
}

2,寻宝 

这就是迷宫题了,上面的点已经说得清楚了,不懂的可以再上去看看

#include<stdio.h>
#include<string.h>
int local[][2]=
{
    {0,1},
    {0,-1},
    {1,0},
    {-1,0}
};
struct node
{
    int num;
    int i;
    int j;
};
int main()
{
	int n, m, a, b, x;
	scanf("%d%d%d%d%d", &n, &m, &a, &b, &x);
	a--;//数组中初始位置要减一
	b--;
	int arr[n][m];//读入地图
    int i=0;
	for (i = 0; i<n; i++)
	{
		int j = 0;
		for (j = 0; j<m; j++)
		{
			scanf("%d", &arr[i][j]);
		}
	}
    struct node queque[10000];
    memset(queque,0,sizeof(queque));
    int head=0,end=1;
    queque[head].num=arr[a][b];
    queque[head].i=a;//记录对应数值的坐标
    queque[head].j=b;
    arr[a][b]=-1;//搜索过的就直接标记
    while(x--)
    {
        int tmp=end;
        while(head<tmp)//一层搜索
        {
           for(int i=0;i<4;i++)//每个点搜索四个方位
           {
               int tmpi=queque[head].i+local[i][0];
               int tmpj=queque[head].j+local[i][1];
               if(tmpi<0||tmpi>=n||tmpj<0||tmpj>=m)//判断边界条件
               {
                   continue;
               }
               else if(arr[tmpi][tmpj]==-1)//搜索过的或者不可走点
               {
                   continue;
               }
               else
               {
                   //存下数值和地址,并将其入队
                   queque[end].num=arr[tmpi][tmpj];
                   queque[end].i=tmpi;
                   queque[end].j=tmpj;
                   end++;
                   arr[tmpi][tmpj]=-1;
               }
           }
            head++;
        }
    }
    int max=0;
    for(int i=0;i<end;i++)
    {
        if(queque[i].num>max)
            max=queque[i].num;
    }
    printf("%d",max);
	return 0;
}

3,龙舌兰酒吧 

具体代码实现如下:

#include<stdio.h>
#include<string.h>
//四个方位
int local[][2]={
    {0,1},
    {0,-1},
    {1,0},
    {-1,0}
};
struct node
{
    char ch;
    int i;
    int j;
};
int judge(struct node *queque,int n)
{
    int i=0;
    for(;i<n;i++)
    {
        if(queque[i].ch!=0)
            return 1;
    }
    return 0;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    char arrp[n][m];//供p寻找
    char arrw[n][m];//供w寻找
    struct node queque[600000];//模拟队列实现
    memset(queque,0,sizeof(queque));
    for(int i=0;i<n;i++)
    {
        getchar();
        for(int j=0;j<m;j++)
        {
            scanf("%c",&arrp[i][j]);
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
            arrw[i][j]=arrp[i][j];
    }
    int pi,pj,wi,wj,tari,tarj;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(arrp[i][j]=='P')//找到P坐标
            {
                pi=i;
                pj=j;
            }
            if(arrp[i][j]=='W')//找到W坐标
            {
                wi=i;
                wj=j;
            }
        }
    }
    
  /*
  此处为测试arrp和arrw是否正常 
         for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            printf("%c",arrw[i][j]);
        }
        printf("\n");
    }
   */
    int countp=0;
    int countw=0;
    int flag1=0;
    //此处开始为两次bfs的实现
    //1.arrp的路径寻找
    int head=0;
    int end=1;
    queque[head].ch=arrp[pi][pj];
    queque[head].i=pi;
    queque[head].j=pj;
    while(judge(queque,end))//判断队列是否为空
    {
        int tmp=end;
        while(head<tmp)
        {
          for(int i=0;i<4;i++)
          {
              int tmpi=queque[head].i+local[i][0];
              int tmpj=queque[head].j+local[i][1];
              if(tmpi<0||tmpi>=n||tmpj<0||tmpj>=m)
                  continue;
              else if(arrp[tmpi][tmpj]=='#')
                  continue;
              else
              {
                  queque[end].ch=arrp[tmpi][tmpj];
                  queque[end].i=tmpi;
                  queque[end].j=tmpj;
                  arrp[tmpi][tmpj]='#';
                  end++;
              }
          }
            queque[head].ch=0;//搜索完出队列
            head++;
        }
        countp++;//搜索完一次走一步
        for(int i=head;i<end;i++)
        {
            if(queque[i].ch=='B')
            {
                flag1=1;
                break;
            }
        }
        if(flag1)
            break;
    }
    memset(queque,0,sizeof(queque));
    head=0;
    end=1;
    queque[head].ch=arrw[wi][wj];
    queque[head].i=wi;
    queque[head].j=wj;
    //2.arrw路径寻找
    int flag2=0;
    while(judge(queque,end))//判断队列是否为空
    {
        int tmp=end;
        while(head<tmp)
        {
          for(int i=0;i<4;i++)
          {
              int tmpi=queque[head].i+local[i][0];
              int tmpj=queque[head].j+local[i][1];
              if(tmpi<0||tmpi>=n||tmpj<0||tmpj>=m)
                  continue;
              else if(arrw[tmpi][tmpj]=='#')
                  continue;
              else
              {
                  queque[end].ch=arrw[tmpi][tmpj];
                  queque[end].i=tmpi;
                  queque[end].j=tmpj;
                  arrw[tmpi][tmpj]='#';
                  end++;
              }
          }
            queque[head].ch=0;
            head++;
        }
        countw++;
        for(int i=head;i<end;i++)
        {
            if(queque[i].ch=='B')
            {
                flag2=1;
                break;
            }
        }
        if(flag2)
            break;
    }
    if(flag1==0||flag2==0)
        printf("-1");
    else
    {
        printf("%d",countp>countw?countp:countw);
    }
    return 0;
}

四,总结 

总体来说,bfs理解了就会很难(doge),bfs也是图论的一个基础算法,希望这篇文章能帮助到你掌握bfs,看到这里不妨给我点个赞吧。之后大概就是一周一篇了。要多输入,才能有输出嘛,多数时间还是要拿来学习的。(还是太菜)。

举报

相关推荐

0 条评论