bfs-迷宫问题

小z身处在一个迷宫中,小z每分钟可以走到上下左右四个方向的相邻格之一。迷宫中有一些墙和障碍物。
同时迷宫中也有一些传送门,当小z走到任意一个传送门时,可以选择传送到其他任意的传送门(传送是不花费时间的),
当然也可以停留在原地。现在小z想知道走出迷宫需要花费的最少时间。
Input
输入第一行为组数T(t<=10)。
对于每组数据第一行为两个整数R和C(1<=R,C<=100)。以下R行每行有C个字符,即迷宫地图。
其中"#“代表墙和障碍物,”."表示空地,"P"表示传送门,"Z"表示小z的起始位置,"W"表示迷宫出口。
对于每组数据保证起始位置和迷宫出口唯一。

Output
对于每组数据,输出走出迷宫的最短时间(单位:分钟)。如果无法走出迷宫则输出"IMPOSSIBLE"。

Sample Input
2
3 4
.Z…
.P#.
##PW
4 4
Z…P

##…
W#.P

Sample Output
2
IMPOSSIBLE

以这个题为例来解释迷宫问题。迷宫问题的解决思路一般都是bfs+优先队列,从起点开始,判断这个点的上下左右是否可行,如果可行,将这个点加入到有点队列中,并且从起点到这个点的步数等于这个点的前一个点的步数+1,直到最后找到终点即可。
但是这个题多了一个传送门,即使多了一个传送门,也不影响解题思路。当在遇到第一个传送门的时候,就可以将起点到所有传送门的步数设置为起点到当前传送门的步数,因为可以从一个传送门传送到任意一个传送门,所以当遇到第一个传送门的时候,就可以这样操作了

#include<bits/stdc++.h>
#define inf 1000000
using namespace std;

typedef pair<int,int>Q;//定义结构体

const int k[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//表示上下左右四个方向

int t,r,c,sx,sy,gx,gy,flag,all,m[105][105],z[105][2];//变量会在下面给出用处

char l[105][105];//接收迷宫

int bfs()
{
    queue<Q>que;//创建一个优先队列
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            m[i][j]=inf;//m数组拥挤记录起点到每个点的步数,先将他们初始化为一个非常大的数


    que.push(Q(sx,sy));//将起点添加到队列中
    m[sx][sy]=0;//起点步数设置成0

    while(que.size())
    {
        Q p=que.front();//取出第一个
        que.pop();

        if(p.first==gx&&p.second==gy)
            break;//遇到终点就结束

        for(int i=0;i<4;i++)//
        {
            int x=p.first+k[i][0],y=p.second+k[i][1];//x,y代表这个点上下左右点的坐标
            if(x>=1&&x<=r&&y>=1&&y<=c&&l[x][y]!='#'&&m[x][y]==inf)//如果满足条件
            {
                que.push(Q(x,y));//将这个点加入到优先队列
                m[x][y]=m[p.first][p.second]+1;

                if(l[x][y]=='P')//如果遇到传送门
                {
                    for(int j=0;j<all;j++){
                        if(m[z[j][0]][z[j][1]]==inf)//如果没有修改过
                    {
                        que.push(Q(z[j][0],z[j][1]));//添加到队列中
                        m[z[j][0]][z[j][1]]=m[x][y];
                    }
                  }
                }

            }
        }
    }
    if(m[gx][gy]==inf)
        return 0;
    else
        return m[gx][gy];
}


int main()
{
    cin>>t;
    while(t--)
    {
        all=0;//用于统计有多少个传送门以及在数组中他们的下标
        scanf("%d %d",&r,&c);
        getchar();//去除缓冲区中的换行符
        for(int i=1;i<=r;i++)
        {
            for(int j=1;j<=c;j++)
            {
                scanf("%c",&l[i][j]);
                if(l[i][j]=='Z')
                   sx=i,sy=j;//记录起点坐标
                if(l[i][j]=='W')
                    gx=i,gy=j;//记录终点坐标
                if(l[i][j]=='P')//如果遇到传送门,就将它储存到数组z中
                    z[all][0]=i,z[all++][1]=j;
            }
            getchar();//去除缓冲区的换行符
        }
        int res=bfs();//开始广搜
        if(!res)
            printf("IMPOSSIBLE\n");
        else
            printf("%d\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42891420/article/details/88015012