【搜索-广搜】 迷宫的最短路径

来源:互联网 发布:张艺兴在EXO的地位知乎 编辑:程序博客网 时间:2024/05/16 07:03

题目:

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

样例输入:

10 10

样例输出:

22

这道题目以及解法均来自《挑战程序设计竞赛(第2版)》第34页-36页;

个人觉得这个例题很好地表现了广度优先搜索是如何与队列先进先出(FIFO)的思想联系起来的,通过不断取得某个状态后能够达到的所有状态并将其加入队列, 并且由于队列本身的特性先加入队列的状态总是先得到处理,这样就达到了一个目的:总是先将需要转移次数更少的状态进行分析处理,换句话说就是总是取得了这个状态的树中更接近根部的节点,又或者是总是让搜索树的广度得到尽可能增加。

/*********代码的建立过程**********/

在这个问题中,找到从起点到终点的最短路径其实就是一个建立队列的过程:

1.从起点开始,先将其加入队列,设置距离为0;

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

3.循环2直到将终点添加到队列中,这说明我们已经找到了路径;

注意到在这个过程中,每次处理的位置所对应的距离是严格递增的,因此一旦找到终点,当时的距离就是最短距离;

同样基于这个原因,搜索可移动到的位置所使用的判断条件中不仅仅是不碰墙壁、不超过边界,还有一个就是没有到达过,因为如果已经到达了这个位置,这说明已经有更短的路径到达这个位置,这次到达这个位置的路径是更差的,不可能得到更好的最终解。

代码:

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;typedef pair<int ,int> P;const int inf=100000000;int n,m;char maze[110][110];int sx,sy,gx,gy;int dx[4]= {0,1,0,-1},dy[4]= {1,0,-1,0};int d[110][110];int bfs(){    for(int i=0; i<n; i++)        for(int j=0; j<m; j++)            d[i][j]=inf;    queue<P> que;    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(nx>=0&&nx<n&&ny>=0&&ny<m&&d[nx][ny]==inf&&maze[nx][ny]!='#')                d[nx][ny]=d[p.first][p.second]+1,que.push(P(nx,ny));        }    }    return d[gx][gy];}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;        }    int ans=bfs();    printf("%d\n",ans);    return 0;}

关于书本的摘录:

(详细见ppt上面的广搜搜索过程)

1.先搜索距离初始状态近的状态;

2.复杂度为O(状态数×转移方式)

3.广搜运用了队列,搜索的时候首先将初始状态加入队列里,此后从队列的最前端取出状态,把从该状态可以转移到的且尚未访问过的部分加入队列,如此往复,直至队列被取空或找到了问题的解;

4.适用于找最短路径,最少操作数;

0 0