链接:https://ac.nowcoder.com/acm/problem/14608

题目描述

after的算法书的遗落在一个叫做AIJ的迷宫中了,这个迷宫有N*M个房间,迷宫的入口为(1,1),算法书遗落在(r,c)。迷宫中的房间有四种状态:空房间、无法进入的房间、有墨菲斯托存在的房间和有莉莉丝存在的房间。墨菲斯托会否定一切,而莉莉丝会诱惑人做一种叫做YK的活动。after是一个意志薄弱的人,他遇到了墨菲斯托和莉莉丝之后,便会变成眼神空洞的超级YK机器人。after每步可以从他当前的房间走至上下左右四个房间的其中一个房间。after害怕变成超级YK机器人,所以要尽快拿到算法书然后从入口逃离。问after最少需要走多少步才可以在不变成超级YK机器人的情况下从入口出发取回算法书并逃离迷宫?

输入描述:

第一行一个正整数T(T<=10),表示共有T组数据。
对于每组数据,第一行四个正整数N,M,r,c(1<=N,M<=1000;1<=r<=N;1<=c<=M)。
接下来N行,每行M个字符,每个表示房间的状态,“.”表示空房间,“*”表示无法进入的房间,“F”表示有墨菲斯托存在的房间,“M”表示有莉莉丝存在的房间。
数据保证(1,1)为“.”。

标题输出描述:

对每组数据输出一行,即after最少需要走的步数。若after无法取回算法书,则输出“IMPOSSIBLE”(不带引号)。

示例1
输入
复制
1
4 4 4 3
..*
*F..
*.
.
*M.F
输出
14

思路

本题说不能同时经过M与F,那么我们就可以经过M与F中的一个,所以我们用两次bfs,一次将M设置为可以走,一次将F设置为可以走。最后在来找两次中走的步数少的就好了。具体的可以看代码中的注释。


#include<iostream>
#include<queue>
#include<cstring>
#include<string.h>
#include<cmath>
using namespace std;
struct Node{
    int x,y;//坐标 
    int step;//步数 
}qq,zz;
int xx[]={-1,0,0,1};
int yy[]={0,-1,1,0};//四个方向 
int vis[1005][1005];
char s1[1005][1005],s[1005][1005];
int n,m,r,c;
int bfs(int qx,int qy,int zx,int zy){
    queue<Node>q;
    Node qq;
    qq.x=1;qq.y=1;qq.step=0;
    q.push(qq);
    vis[1][1]=1;
    while(!q.empty()){
        Node now=q.front();
        q.pop();
        if(now.x==zx&&now.y==zy){
            return now.step;
        }//如果到达,则返回当前步数 
        for(int i=0;i<4;i++){
            qq.x=now.x+xx[i];
            qq.y=now.y+yy[i];
            if(qq.x>0&&qq.y>0&&qq.x<=n&&qq.y<=m&&s1[qq.x][qq.y]=='.'&&!vis[qq.x][qq.y]){
                vis[qq.x][qq.y]=1;
                qq.step=now.step+1;
                q.push(qq);
            }//如果可以到达,则标记为已经走过,步数为当前步数+1,并将结构体加入到队列中 
        }
    }
    return -1;//若q为空也没到达,则返回-1 
} 
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>m>>r>>c;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>s[i][j];
                if(s[i][j]=='F'){
                    s1[i][j]='.';
                }
                else{
                    s1[i][j]=s[i][j];
                }//将s1置为.与F可走 
            }
        }
        memset(vis,0,sizeof(vis));
        int a1=bfs(1,1,r,c);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(s[i][j]=='M'){
                    s1[i][j]='.';
                }
                else{
                    s1[i][j]=s[i][j];
                }//将s1置为.与M可走 
            }
        }
        memset(vis,0,sizeof(vis));
        int a2=bfs(1,1,r,c);
        if(a1==-1&&a2==-1){
            cout<<"IMPOSSIBLE"<<endl;
        }//如果都小于0,则不肯能到达r,c 
        else if(a1<0||a2<0){
            cout<<max(a1,a2)*2<<endl;
        }//如果有一个小于0,则答案为大于0的 
        else{
            cout<<min(a1,a2)*2<<endl;
        }//如果答案都大于0,则为步数小的
        //因为是来回,所以答案乘2 
    } 
    return 0;
}