题目描述
乔在迷宫中工作。不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划。请帮助乔逃离迷宫。根据乔在迷宫中的位置以及迷宫的哪个方块着火,你必须确定火焰烧到他之前,乔是否可以离开迷宫,如果能离开他能跑多快。
乔和火每分钟移动一个方格,上、下、左、右,四个方向中的一个。火势向四个方向同时蔓延。乔可以从迷宫的任何一个边界逃离迷宫。无论是乔还是火都不会到达有墙的位置。
输入
第一行输入包含一个整数,即测试次数
每个测试用例的第一行包含两个
整数R和C,用空格分隔,1≤R,C≤1000
下面R行中,每一行都包含C个字符,以及每个字符是以下之一:
# 代表墙
. 代表空地,火和乔是可通行的
J 乔在迷宫中最初的位置,火和乔是可通行的
F 代表火
在每组测试中只有一个J
输出
对于每个测试用例,如果在火蔓延的时候烧到了乔,则乔无法逃出迷宫,输出'IMPOSSIBLE'如果乔能逃出迷宫,则输出乔最快可以在几分钟内安全逃出迷宫,每组输出占一行
样例输入
2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F
样例输出
3
IMPOSSIBLE
在我刚开始学深搜的时候,这道题卡了我一天。
下面就为什么做不出来进行一次分析:
1、刚开始没有考虑到有多处火
2、用%c进行输入,每次输入出现‘F’的时候直接用bfs进行分析,这样导致后面没有输入的数据不能被分析进去。
而排出了这些小BUG后,再分析起来就十分顺利了。
大致思路就是让火先跑,然后人再跑,边跑边判断。
首先是标记火与乔出发的地点,然后让各处火先跑,那么就有可能出现几处火到达同一个地方,举个例子,现在远处有一个苹果,几个人跑到远处去拿那个苹果,肯定会有一个人先拿到这个苹果,那么即使后面的人再来到这个地方也没有苹果了。
也就是说,对于一个点,要取的是这几个火到达这个点所用时间的最小值。
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<string.h>
#include<stdio.h>
using namespace std;
#define INF 0x3f3f3f3f
char a[1005][1005];
int indx[1005][1005];
int fire_fire[1005][1005];
int fire_number[1005][1005];
int begin_x,begin_y;
int mov[4][2]={0,1,0,-1,1,0,-1,0};
int n,m;
struct xiao
{
int x,y,step;
};
struct xiao s,e;
queue<xiao>q;
int judge(int x,int y)
{
if(x<0||x>=n||y<0||y>=m)
return 1;
return 0;
}
void bfs_fire()
{
//用fire_number去存储出现的最小的次数
memset(indx,0,sizeof(indx));
while(!q.empty())
{
xiao mm;
s=q.front();
q.pop();
for(int i=0;i<4;++i)
{
mm.x=s.x+mov[i][0];
mm.y=s.y+mov[i][1];//这里的e代表的是火四周的范围
if(judge(mm.x,mm.y))
{
continue;
}
if(a[mm.x][mm.y]=='#'||indx[mm.x][mm.y]||a[mm.x][mm.y]=='F'||fire_fire[mm.x][mm.y]!=-1)
continue;
indx[mm.x][mm.y]=1;
mm.step=s.step+1;
fire_fire[mm.x][mm.y]=mm.step;
if(fire_fire[mm.x][mm.y]<fire_number[mm.x][mm.y])
{
fire_number[mm.x][mm.y]=fire_fire[mm.x][mm.y];
}
else
return ;
q.push(mm);
}
}
return ;
}
void bfs()
{
queue<xiao>p;
memset(indx,0,sizeof(indx));
//现在这一步的操作进行的判断是在火之前到达周围的点还是火之后到达周围的某一个点
//进行队列的清空操作,方便下面的工作的开展
e.x=begin_x;
e.y=begin_y;
e.step=0;
if(e.x==0||e.x==n-1||e.y==0||e.y==m-1)
{
printf("1\n");
return ;
}
indx[e.x][e.y]=1;
//现在是已经找到了点。
p.push(e);
while(!p.empty())
{
e=p.front();
p.pop();
for(int i=0;i<4;++i)
{
int dx=e.x+mov[i][0];
int dy=e.y+mov[i][1];
//现在是已经找到了下一个点的位置,那么接下来就是进行判断了
if(judge(dx,dy))
{
//如果说越界的话,就执行
printf("%d\n",e.step+1);
return ;
}
if(indx[dx][dy]||a[dx][dy]=='#'||a[dx][dy]=='F'||e.step+1>=fire_number[dx][dy])
continue;
//现在说如果不越界,那么就要一步步地进行判断
s.step=e.step+1;
s.x=dx;
s.y=dy;
indx[s.x][s.y]=1;
//现在代表的是步数增加一步。
p.push(s);
}
}
printf("IMPOSSIBLE\n");
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(indx,0,sizeof(indx));
memset(fire_fire,-1,sizeof(fire_fire));
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
fire_number[i][j]=10000000;
}
}
for(int i=0;i<n;++i)
{
scanf("%s",a[i]);
}
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
if(a[i][j]=='J')
{
begin_x=i;
begin_y=j;
}
else if(a[i][j]=='F')
{
//找到火就遍历一遍
while(!q.empty())
q.pop();
s.x=i;
s.y=j;
s.step=0;
q.push(s);
memset(indx,0,sizeof(indx));
memset(fire_fire,-1,sizeof(fire_fire));
indx[s.x][s.y]=1;
fire_fire[s.x][s.y]=0;//代表火的步数
bfs_fire();
}
}
}
bfs();
}
return 0;
}
关于这个应该还有一个思考,那就是为什么不用dfs而用bfs。