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