UVA-11624 Fire!(BFS预处理+BFS寻找结果)

题意:

Joe在迷宫里(咱也不知道他为啥去迷宫,咱也不敢问啊),然后呢还有火。Joe想逃出去,要不就被火烧到了。每个时刻,火都会向四周蔓延,那么Joe能不能逃出去,能输出最少的时间,不能就gg了,输出IMPOSSIBLE。 

注意题目中有一句话:There will be exactlu one J int each test case.

就是说只有一个Joe,那么火呢?肯定是多个啊。(坑)

思路:

先把每个时刻的火bfs处理一下,然后在bfs一下Joe的路径能不能出去。到边界就出去了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<algorithm>
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define scll(x) scanf("%lld",&x)
#define mem(x,a) memset(x,a,sizeof x)
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

const int maxn = 1500;

char mp[maxn][maxn];
int fire_time[maxn][maxn];    // 记录每个时刻的火
bool vis[maxn][maxn];
int dir[][2]={0,1,1,0,0,-1,-1,0};
int n,m;

typedef pair<int,int> PII;    // 由于火源不止一个,那么需要保存每个火源
queue<PII> Qfire;    // 把火源直接放进队列bfs就OK了

struct node{
    int x,y;
    int v;
};

void fire_bfs(){
    mem(vis,0);
    while(!Qfire.empty()){
        PII f = Qfire.front();
        Qfire.pop();
        int x = f.first;
        int y = f.second;
        vis[x][y] = 1;
        for(int i=0;i<4;i++){
            int xx = x+dir[i][0];
            int yy = y+dir[i][1];
            if(xx>=0 && xx<n && yy>=0 && yy<m && !vis[xx][yy] && mp[xx][yy]!='#'){
                vis[xx][yy]=1;
                fire_time[xx][yy]=fire_time[x][y]+1;
                Qfire.push(PII(xx,yy));
            }
        }
    }
}

void joe_bfs(int x,int y){
    mem(vis,0);
    queue<node> Q;
    node t;
    t.x = x;
    t.y = y;
    t.v = 1;
    vis[x][y]=1;
    Q.push(t);
    while(!Q.empty()){
        node f = Q.front();
        Q.pop();
        //cout<<f.x<<"----"<<f.y<<endl;
        if(f.x+1==n || f.y+1==m || f.x==0 || f.y==0){
            printf("%d\n",f.v);
            return ;
        }
        node tmp;
        for(int i=0;i<4;i++){
            int xx = f.x+dir[i][0];
            int yy = f.y+dir[i][1];
            if(xx>=0 && xx<n && yy>=0 && yy<m && !vis[xx][yy] && mp[xx][yy]=='.' && fire_time[xx][yy]>f.v+1){
                // fire_time[xx][yy]>f.v+1下一次肯定是去到比自己大至少2的时间点,才不会被烧
                // 例如此时人的时间为1,则下一步人的时间是2,没问题吧,那么人不能去一个时间点小于等于2的带,因为那个点一定是火
                vis[xx][yy]=1;
                tmp.x = xx,tmp.y = yy,tmp.v = f.v+1;
                Q.push(tmp);
            }
        }
    }
    printf("IMPOSSIBLE\n");
}

int main(){
    int t;sc(t);
    int jx,jy,fx,fy;
    while(t--){
        mem(mp,0);
        mem(fire_time,INF);
        scc(n,m);
        for(int i=0;i<n;i++){
            getchar();
            for(int j=0;j<m;j++){
                mp[i][j] = getchar();
                if(mp[i][j]=='J'){  // 人
                    jx=i,jy=j;
                }
                if(mp[i][j]=='F'){  // 火
                    //fx=i,fy=j;
                    Qfire.push(PII(i,j)); //多个火源、、坑老子啊ToT
                    fire_time[i][j]=1;
                }
            }
        }
        fire_bfs();
//        for(int i=0;i<n;i++){ //看看处理完的火的情况
//            for(int j=0;j<m;j++){
//                cout<<fire_time[i][j];
//            }
//            cout<<endl;
//        }
        joe_bfs(jx,jy);
    }
}

总结:

虽然ac了但是有一点不是太明白,如果一个火源很好理解,处理完就好了,那么多个火源,在处理第二个火源时是否会存在一个点p,这个点通过A火源是在第三个时刻到达的,而还可以通过B火源第二个时刻到达,但是A火源首先遍历会让B火源无法访问点p.那么人是否有可能在第二个时刻到了p点,其实如果从B火源燃烧过来这个点p也正好着火,是不能到达的。但是由于我们先处理了A火源,导致p点在第三时刻才有火,反而可以到达了。是不是有点小瑕疵。也可能是我哪里想的不对。望大家指正。感谢!

猜你喜欢

转载自blog.csdn.net/qq_40099908/article/details/99572513