4.2 bfs 广度优先搜索

广度优先算法 Breadth First Search BFS

深度优先算法的兄弟,包含另外一种搜索思维
也叫宽度优先算法

概述

与深度优先算法不同,广度优先算法注重于"对所有情况的分析搜索"
如果是深度优先算法是刨根问底地分析每种情况,
广度优先就是在在层层扩展中找到题解

还是之前的问题,我们想在n*m的迷宫中找到起点到终点的最短路径

分析

我们的核心思想是分析扩展时每发现一个点,就将这个点加入到队列中,直到到达终点
另外,为防止一个点被多次走到,我们还要一个数组来记录一个点是否被走到

队列与搜索路径

我们决定使用一个队列来模拟搜索过程,我们需要:
1.两个参数x,y代表点坐标
2.一个参数s代表我们走过的步数
3.某一点之前的,用于计算路径 (本题不需要计算路径,就省去这部分)

实现如下:

    struct note {
        int x ; //横坐标
        int y ; //纵坐标
        int s ; //步数
    };

初始化

我们设定相关数据完成队列,并且对各个条件进行初始化

    struct node que[2501] ; //地图为50*50,设置为2501就不会越界了
    int head,tail ;
    int a[51][51] = {0} ; //用于存储地图    
    int book[51][51] = {0} ; //记录拿一些点已经在队列中了,防止点的重复扩展 
                            //0代表还没走过

    //设置队列 
    head = 1 ; 
    tail = 1 ;

    //先将默认起点(1,1)加入
    que[tail].x = 1 ;
    que[tail].y = 1 ;
    que[tail].s = 0 ;
    tail++;
    book[1][1] = 1 ;

开始搜索

我们以(1,1) -> (1,2)为例解释怎么进行点的判断
1.尝试走到(1,2)

    tx = que[head].x + 0; 
    ty = que[head].y + 1;

2.判断
主要是两点,一是是否越界,二是是否为障碍,三是是否已经走过

    if(tx<1 || tx>n || ty<1 || ty >m){
        continue ; 
    }

    if(a[tx][ty] == 0 && book[tx][ty]){
        //入队
    }

入队

    if(a[tx][ty] == 0 && book[tx][ty] == 0 ){
        //入队
        book[tx][ty] = 1 ;  //顺带一提,宽度优先中只会入队
                            //和深度优先不同,宽度优先没有把book还原的操作
        
        //插入新的点到队列中
        que[tail].x = tx ; 
        que[tail].y = ty ;
        qye[tail].s = que[head].s + 1;
        tail++ ;
    }

更新

我们再用相同的做法判断(2,1),至此我们已经搜索了(1,1)周围的所有点
现在我们需要更新(1,1),这个点已经没用了,我们将它出队

    head++;

之后,我们新的出发点就变成了(1,2),对它进行搜索,然后再更新,再搜索…直到到达终点

另外,这里的按四个方向搜索的办法和深度是一样的

    int next[4][2] = {  {0,1},{1,0},{0,-1},{-1,0}};

完整代码

    #include<stdio.h> 

    struct note {
        int x ; //横坐标
        int y ; //纵坐标
        int s ; //步数

        int f ; //父编号,暂时还用不到,之后的代码请先无视f
    };

    int main(){
        struct note que[2501] ;
        int a[51][51] = {0} , book[51][51] = {0};

        //定义一个用于表示方向的数组    
        int next[4][2] = {  {0,1},  //向右
                            {1,0},  //向下
                            {0,-1}, //向左
                            {-1,0}  //向上
                            };

        int head,tail ;
        int i,j,k,n,m,startx,starty,p,q,tx,ty,flag ; 

        //读入参数
        scanf("%d %d",&n,&m) ;
        for(i=1;i<=m;i++)
            for(j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        scanf("%d %d %d %d",&startx,,&starty,&p,&q);

        //初始化队列
        head = 1 ; 
        tali = 1 ;

        //往队列插入迷宫入口坐标
        que[tail].x = startx ;
        que[tail].y = statty ;
        que[tail].f = 0 ;
        que[tail].s = 0 ;
        tail++;
        book[startx][starty] = 1 ;

        flag = 0 ; //0表示还没到达,1表示到达终点

        //当队列不为空的时候执行循环
        //为什么是“不为空”时执行,请看后面的代码

        while(head < tail){
            for(k=0;k<=3;k++){
                //计算下一个点
                tx = que[head].x + next[k][0] ; 
                ty = que[head].y + next[k][1] ;

                //对应判断,与深度优先相同
                if(tx<1 || tx>n || ty<1 || ty>m)    continue ; 

                if(a[tx][ty] == 0 && book[tx][ty] == 0){
                    book[tx][ty] =1 ; //标记已经走过

                    que[tail].x = tx ; 
                    que[tail].y = ty ;
                    que[tail].f = head ; 
                    que[tail].s = que[head].s +1;
                    tail ++ ;
                }

                if(tx == p && ty == q){
                    //如果到达目标点了,停止扩展,结束,退出循环
                    flag = 1 ;
                    break ;
                }
            }

                if(flag ==1)
                    break ; 
                
                head++ ; //一个点拓展结束后,对后面的点再拓展
        }

        //打印步数
        //值得注意的是,tail是指向“最后一个位置的下一个位置”,因此我们要-1

        printf("%d",que[tail-1].s);

        getchar();getchar();
        return 0 ;

        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值