迷宫求最小步数_BFS_包括路径输出(非函数版)

事实上,因为bfs并不是递归求解,那么我就暂时不想写函数版的了,没啥意义对吧,,,

思路就是《啊哈算法》书上关于bfs的解释,在书第88-95页

接下来是我的代码和解释(代码和书上的稍微有一点点区别,但思路是一致的)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<string>
#include<cmath>

/*
3 3
0 0 0
1 0 1
1 0 0
1 1
3 3
*/

using namespace std;

struct note
{
    int x,y;
    int fa;
    int s;//步数
};
note que[2505];
int a[55][55],book[55][55];
int next[4][2]={ {1,0},{-1,0},{0,1},{0,-1} };

int main()
{
    int head,tail;
    int n,m,startx,starty,p,q;//迷宫的宽和长,起始点的x和y,终点的x和y
    int flag;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    scanf("%d%d%d%d",&startx,&starty,&p,&q);
    head=tail=0;
    que[tail].x=startx;
    que[tail].y=starty;
    que[tail].fa=-1;
    //之所以让起点的fa=-1是因为:如果说令起点的fa=0,那么由于程序在录入某一步走到哪里时,这一步的fa等于head,但在走完第一步后将第一步的fa想与head联系时,
    //!!此时的 head 还没有来得及++ ,即仍为0。 故而bfs之后,(如果说令起点的fa=0),那么fa=0的note其实有两个点,一个是起点,一个是第一步的这个点,但由于我们是用回溯的方式来找路径的,
    //所以第一步肯定比起点先被找到,由于条件是tail!=0(因为我们假设令起点的fa=0,那循环条件肯定是:( 在打印完起点(即打印到<fa=0>这点)后停下) )即:条件 tail!=0 时可参与循环,否则跳出循环。
    //所以到第一个tail等于0的点(即第一步的这个点),循环停止,终止输出(故,当我们令起点的fa=0时,循环结束时,不仅要补充输出起点,还要补充输出第一步的位置点)。
    //(这样就很麻烦啊,所以我们在给边界,尤其是这个边界值要作为一些操作的判断条件时,我们就尽量挑一些特殊的值,以免出现以上说的这种情况->如果给起点的fa赋值为-1,那我上面这一堆不就不用再费时间想了吗^-^)
    que[tail].s=0;
    tail++;
    book[startx][starty]=1;
    flag=0;
    if(startx==p&&starty==q)//由于我们下面的这个 while(head<tail) 循环里面,没有对未处理的(即 未对该点进行 下一步尝试 的操作)que[tail].x与gx和que[tail].x与gy之间的比较,就直接让que[tail].x+next[i][0],que[tail].y+next[i][1]
    {
                            //(即,直接默认起点与终点不是一个点<因为如果起点终点不是同一个点,那么不加 if(startx==p&&starty==q) 这条语句完全没有问题,因为只要不是第一次还没有操作时的tail点(即起点)就到达了终点,
                            //那么在此之后每一个tail都会在其操作完了之后 判断操作后的该点是否到达终点,也就是说 while(head<tail) 循环里面 就少第一次未操作时的的判断>,进而直接对tail点开始下一步走哪里的尝试)。
                            //这样的话,如果不加 if(startx==p&&starty==q) 这条语句进行判断,那么当起点与终点是同一个点时,那么输出结果必然不为0
                            //dfs之所以不需要额外的这样一条判断语句是因为,每次进入dfs的函数中,第一个语句就是判断的就是当前点是否已经达到了终点(故而,就算起点终点为同一个点,进入第一个dfs函数中时,就会进行判断,进而返回0)
        cout<<0<<endl;
    }
    else
    {
        while(head<tail)
        {
            for(int i=0;i<4;i++)
            {
                int tx=que[head].x+next[i][0];
                int ty=que[head].y+next[i][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].fa=head;
                    que[tail].s=que[head].s+1;
                    tail++;
                }
                if(tx==p&&ty==q)
                {
                    flag=1;
                    break;
                }
            }
            if(flag)    break;
            head++;
        }
        if(flag)
        {
            cout<<"最少需要走 "<<que[tail-1].s<<" 步"<<endl;//由于每次都是先tail++,然后再判断此次往队列里塞的note是不是终点,就算是终点,break了tail也已经加过了,所以在输出的时候,就必然要把多加的那个1从tail中减下去,才能指向正确的 ”终点“在队列里的位置
            cout<<"路径为:"<<endl;
            tail--;//彻底的把那个多的1从tail中减去
            printf("(%d,%d)\n",p,q);
            tail=que[tail].fa;
            while(que[tail].fa!=-1)
            {
                printf("(%d,%d)\n",que[tail].x,que[tail].y);
                tail=que[tail].fa;
            }
            printf("(%d,%d)\n",que[tail].x,que[tail].y);//就是把fa=-1这个点,即起点这个点输出出来
        }
        else
            cout<<"走不出迷宫"<<endl;
    }

    return 0;
}

这个就是最最朴素的的bfs啦,然后bfs还有优化,学会了再写…………

猜你喜欢

转载自blog.csdn.net/qq_41764621/article/details/81707691