题目链接
https://vjudge.net/contest/353188#problem/K
大体题意就是在火烧到自己之前逃离迷宫,#代表墙,.代表可以走的路,J代表人的起点,F代表火的起点。
具体可以参照样例
1 //样例个数
4 4
.###
#JF#
#…#
#…#
题意比较明了,可以让火bfs一遍,记录能到的每一个点的时间。
但是这个题简直就是英语渣渣的噩梦,在oj上WA了无数次也没找到错在了哪里,去网上查了查,看到题解的第一句话我就懂了,原来火有多个起点,也就是F不一定只有一个,可能有多个F,它题目中火那个单词加了s,(我连那个是火的单词都不知道,233333).既然有多个起点,那么可能有多个火到达同一个点 ,如果对于每一个F都bfs一遍取每一个点的最小值的话,会超时,而加了优化就有可能WA掉(亲身经历),那么干脆直接把这些点一起放到队列里面,这样就可以完美的解决了.
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1010;
int t,n,m,x1,y1,x2,y2;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int pis[N][N];
char str[N][N];
bool st[N][N];
struct Node
{
int x,y,step;
};
queue<Node>p;//定义全局的队列,共用一个st
int bfs1(int x,int y)
{
memset(st,false,sizeof st);
queue<Node>q;
Node fis;
fis.x=x,fis.y=y,fis.step=0;
st[x][y]=true;
q.push(fis);
while(q.size())
{
Node cur=q.front();
q.pop();
if(cur.x==1||cur.x==n||cur.y==1||cur.y==m)
return cur.step;
Node next;
next.step=cur.step+1;
for(int i=0;i<4;i++)
{
int xx=next.x=cur.x+dir[i][0];
int yy=next.y=cur.y+dir[i][1];
if(xx<1||xx>n||yy<1||yy>m||st[xx][yy]||str[xx][yy]=='#')
continue;
if(pis[xx][yy]<=next.step)//判断是否能在火到之前到达这个点
continue;
st[xx][yy]=true;
q.push(next);
}
}
return -1;
}
void bfs2()
{
while(p.size())
{
Node cur=p.front();
p.pop();
pis[cur.x][cur.y]=cur.step;
Node next;
next.step=cur.step+1;
for(int i=0;i<4;i++)
{
int xx=next.x=cur.x+dir[i][0];
int yy=next.y=cur.y+dir[i][1];
if(xx<1||xx>n||yy<1||yy>m||st[xx][yy]||str[xx][yy]=='#')
continue;
st[xx][yy]=true;
p.push(next);
}
}
}
int main()
{
cin>>t;
while(t--)
{
memset(pis,0x3f,sizeof pis);//初始化距离为正无穷
memset(st,false,sizeof st);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
for(int j=1;j<=m;j++)
if(str[i][j]=='J')
x1=i,y1=j;
else if(str[i][j]=='F')
{
p.push({i,j,0});//入队
st[i][j]=true;
}
}
bfs2();
int res=bfs1(x1,y1);
if(res==-1)
printf("IMPOSSIBLE\n");
else
printf("%d\n",res+1);//看样例可以知道出去还需要一步
}
return 0;
}