题意
给定一个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;
}