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點在第三時刻纔有火,反而可以到達了。是不是有點小瑕疵。也可能是我哪裏想的不對。望大家指正。感謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章