• 【BFS】迷宫的最短路径问题


    给定一个大小为N*M的迷宫,由通道('.')和墙壁('#')组成,其中通道S表示起点,通道G表示终点,每一步移动可以达到上下左右中不是墙壁的位置。试求出起点到终点的最小步数。(本题假定迷宫是有解的)

    (N,M<=100)

    样例输入:

    10 10

     

    # S # # # # # # . #
    . . . . . . # . . #
    . # . # # . # # . #
    . # . . . . . . . .
    # # . # # . # # # #
    . . . . # . . . . #
    . # # # # # # # . #
    . . . . # . . . . .
    . # # # # . # # # .
    . . . . # . . . G #


    样例输出:

    22

    分析:像最短路径最少操作之类的问题可以使用宽度优先搜索

    关于宽度优先搜索:

    宽度优先搜索按照距开始状态由近及远的顺序进行搜索,那么它是怎么做到的呢?

    搜索时首先将初始状态加到队列里,此后从队列的最前段不断取出状态(所以每次处理的都是离初始状态最近的),把从该状态可以转移到的状态中尚未访问过的部分加入队列,如此往复,直至队列被取空或找到了问题的解。

    回到本题加深一下对宽度优先搜索的理解:

    1、本题的状态是所在位置的坐标,所以可以构造pair来表示状态。

    2、因为要求最小步数,所以想到用一个数组d[N][M]把移动时的步数记下来。

    3、从队列首端取出位置,将从这个位置能够到达的位置加入队列,并且让这些位置的距离为上一个位置的距离加上1

    4、循环3直到从队列首端取出的是终点,这说明我们已经找到了路径

    注:每次处理的位置所对应的步数是严格递增的,所以,如果已经到达过这个位置不用再向这个位置走,因为再走一遍还是到这个位置那么这个路径的步数肯定比上一次到达这个位置的路径的步数多,所以才能实现一旦找到终点,当时的步数就是最小步数。

    5、所以要将已经访问过的状态标记出来,用充分大的常数INF初始化数组d,到达的位置会有步数,没到达的则是INF.

    画了个不是很严谨的图,对着代码看下一应该很好理解,通过图发现只有最短路径被延续下去直到终点。

    代码如下:

    #include <iostream>
    #include <stdio.h>
    #include <queue>
    #define MAX_N 100
    #define MAX_M 100
    using namespace std;
    const int INF = 100000000;
    typedef pair<int,int> P;
    char maze[MAX_N][MAX_M+1];
    int N,M;
    int sx,sy;
    int gx,gy;
    int d[MAX_N][MAX_M];
    int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    void bfs();
    int main()
    {
        scanf("%d%d",&N,&M);
        for(int i=0;i<N;i++){
            scanf("%s",maze[i]);
        }
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                if(maze[i][j]=='S')
                {
                    sx=i;
                    sy=j;
                }
                if(maze[i][j]=='G'){
                    gx=i;
                    gy=j;
                }
            }
        }
        bfs();
    printf("%d",d[gx][gy]);
        return 0;
    }
    
    void bfs(){
        queue<P> que;
        for(int i;i<N;i++){
            for(int j=0;j<M;j++){
                d[i][j]=INF;
            }
        }
        que.push(P(sx,sy));
        d[sx][sy]=0;
        while(que.size()){
        //从队列的最前端取出元素
        P p=que.front(); que.pop();
            if(p.first==gx&&p.second==gy)break;
        for(int i=0;i<4;i++){
                int nx=p.first+dx[i],ny=p.second+dy[i];
                if(maze[nx][ny]!='#'&&nx>=0&&nx<N&&ny>=0&&ny<M&&d[nx][ny]==INF){
                    que.push(P(nx,ny));
                    d[nx][ny]=d[p.first][p.second]+1;
                }
            }
    
        }
    }
    祝你早日攒够失望,然后开始新的生活。
  • 相关阅读:
    barcode制作条形码及破解
    软件敏捷架构师
    软件需求分析三步走
    GDI+显示GIF动画
    CSpinButtonCtrl的弱智问题
    [C++] STL里面的map
    [C#] 再议Exception
    [C++] unsigned是麻烦制造者
    用GDI+转BMP为WMF、EXIF、EMF格式
    [C++] 编译时的warning
  • 原文地址:https://www.cnblogs.com/LuRenJiang/p/6917718.html
Copyright © 2020-2023  润新知