题意
给定一个n*m的矩阵,其中‘J’表示人,‘F’表示火,‘#’表示墙,‘.’表示通道。火每分钟朝四周蔓延一个格子,人每分钟也只能从四周走一个格子,为墙的格子火和人都不能走。求人能否逃出矩阵。
解题
先从火开始进行bfs,并用d[i][j]表示火到达第i行第j列所需的最短时间。再从人开始bfs,加一个到下一个格子的时间必须小于d[i][j]的限制。
一开始TLE了一发,想了想就进行了两次bfs是不太会TLE的。重新读题注意到题目特别指出人只有一个,也就是说火可能有多个。所以,按我原来的写法,对每个火都进行了一次bfs,超时就是可以预见的了。故一开始将火放入队列,只进行一次bfs即可解决超时问题。
AC代码
//160ms
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;const int maxn=1e3+100;
char s[maxn][maxn];
int n,m;
int d[maxn][maxn];
int dir[4][2]={
0,1,0,-1,1,0,-1,0};
bool vis[maxn][maxn];
struct node
{int x,y,t;node(int x,int y,int t):x(x),y(y),t(t){}
};
bool valid(int x,int y)
{return x>=0 && x<n && y>=0 && y<m && !vis[x][y] && s[x][y]=='.';
}
queue<node> Q;
void bfs(char ch,int u,int v)
{memset(vis,false,sizeof(vis));if(ch=='F') memset(d,0x3f,sizeof(d));if(ch=='J'){vis[u][v]=true;Q.push(node(u,v,0));}while(!Q.empty()){node now=Q.front();Q.pop();int x=now.x,y=now.y,t=now.t;// cout<<x<<" " <<y<<" "<<t<<endl;if(ch=='J'){if(x==n-1 || y==m-1 || x==0 || y==0){printf("%d\n",t+1);return ;}}for(int i=0;i<4;i++){int fx=x+dir[i][0],fy=y+dir[i][1];// cout<<"fx="<<fx<<" "<<"fy="<<fy<<endl;if(!valid(fx,fy)) continue;if(ch=='J' && d[fx][fy]<=t+1) continue;vis[fx][fy]=true;if(ch=='F') d[fx][fy]=t+1;Q.push(node(fx,fy,t+1));}}if(ch=='J') printf("IMPOSSIBLE\n");
}int main()
{int T;scanf("%d",&T);while(T--){while(!Q.empty()) Q.pop();scanf("%d%d",&n,&m);for(int i=0;i<n;i++)scanf("%s",s[i]);for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(s[i][j]=='F'){Q.push(node(i,j,0));// bfs('F',i,j);}bfs('F',0,0);for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(s[i][j]=='J') bfs('J',i,j);}return 0;
}