虽然显然是bfs,但是写的时候还是有问题的
首先是预处理火焰扩散的时间和位置
原本是对每一个火焰进行bfs,对于下一步火焰扩散的格子(nx, ny)
如果有d(nx, ny) < d(x,y)+1,则不加入队列中
最后得到一个数组firetime[x][y]表示火焰到(x,y)的最短时间
这种方法虽然也能有解,不过太慢
刘汝佳的方法是一开始就把所有火焰插到队列里,作为第一层
所以我对bfs认识还是太浅。
lrj对人和火焰分别做两个互不相关的bfs
最后只要看边界上一个能够到达的点,火焰和人谁先到
人先到的话就更新ans
本来感觉这种方法是有问题的,因为火焰可能会在路上把人拦截
后来想想这样就意味着火焰一定会先到。
所以算法是正确的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <map>
using namespace std;
#define INF 1e9
#define maxn
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
int t, r, c;
char mat[1005][1005];
bool vis[1005][1005][2];
int d[1005][1005][2];
int dir[4][2]={{1,0}, {-1,0}, {0,1}, {0,-1}};
struct node{
int x, y;
node(int x=0, int y=0):x(x),y(y){};
};
vector<node> v;
queue<node> q;
int bfs(int kind){
node u;
while(!q.empty()){
u = q.front(), q.pop();
int nx, ny;
for(int i=0; i<4; i++){
nx = u.x+dir[i][0];
ny = u.y+dir[i][1];
if(nx>=0 && nx<r && ny>=0 && ny<c && !vis[nx][ny][kind] && mat[nx][ny]=='.'){
q.push(node(nx, ny));
vis[nx][ny][kind] = 1;
d[nx][ny][kind] = d[u.x][u.y][kind]+1;
}
}
}
return -1;
}
int ans;
void check(int x, int y){
if(mat[x][y]!='.' && !vis[x][y][0] )
return;
if( !vis[x][y][1] || d[x][y][0]<d[x][y][1] )
ans = min(ans, d[x][y][0]);
}
int main(){
// freopen("a.txt","r",stdin);
// freopen(".out","w",stdout);
cin>>t;
while(t--){
cin>>r>>c;
v.clear();
mset(d);
mset(vis);
for(int i=0; i<r; i++){
scanf("%s", mat[i]);
for(int j=0; j<c; j++){
if(mat[i][j]=='J')
{
q.push(node(i, j));
vis[i][j][0] = 1;
mat[i][j]='.';
}
if(mat[i][j]=='F'){
mat[i][j]='.';
v.push_back(node(i, j));
}
}
}
bfs(0);
//跑完以后q是空的
for(int i=0; i<v.size(); i++){
vis[v[i].x][v[i].y][1] = 1;
q.push(v[i]);
}
bfs(1);
ans=INF;
for(int i=0; i<r; i++){
check(i,0);
check(i,c-1);
}
for(int i=0; i<c; i++){
check(0,i);
check(r-1,i);
}
if(ans>=INF) puts("IMPOSSIBLE");
else printf("%d\n", ans+1);
}
return 0;
}