题目描述(已转换成中文)
乔在迷宫中工作。不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划。请帮助乔逃离迷宫。根据乔在迷宫中的位置以及迷宫的哪个方块着火,你必须确定火焰烧到他之前,乔是否可以离开迷宫,如果能离开他能跑多快。
乔和火每分钟移动一个方格,上、下、左、右,四个方向中的一个。火势向四个方向同时蔓延。乔可以从迷宫的任何一个边界逃离迷宫。无论是乔还是火都不会到达有墙的位置。
输入格式
第一行输入包含一个整数,即测试次数,每个测试用例的第一行包含两个整数R和C,用空格分隔,1≤R,C≤1000
下面R行中,每一行都包含C个字符,以及每个字符是以下之一:
# 代表墙
. 代表空地,火和乔是可通行的
J 乔在迷宫中最初的位置,火和乔是可通行的
F 代表火
在每组测试中只有一个J
输出格式
对于每个测试用例,如果在火蔓延的时候烧到了乔,则乔无法逃出迷宫,输出’IMPOSSIBLE’如果乔能逃出迷宫,则输出乔最快可以在几分钟内安全逃出迷宫,每组输出占一行
输入输出样例
输入
2
4 4
#JF#
#…#
#…#
3 3
#J.
#.F
输出
3
IMPOSSIBLE
题目链接
分析:
这道题是需要进行双bfs,大致题意是人要在火还没烧到方格前经过方格,当他走到迷宫的边界的时候即视为逃出来了迷宫且不会被火烧,求人逃出迷宫所需的最少时间。首先读入测试次数,在读入每个方格具体的字符的时候,记录人所在的初始位置(p1, q1),因为人的初始位置只有一个,所以可以用两个变量记录其坐标,但火可能不止一堆,所以只能在后续的bfs1函数中记录。
接着主函数调用bfs1函数,创建一个数据类型为node的队列来存放火烧过方格的坐标。因为有多组测试,所以在bfs1在处理各个坐标之前应该对vis1数组元素都初始化为-1,为什么要初始化为-1,而不是像之前一些bfs的题目直接清零?因为火有初始位置,没经过任何时间火就已经在方格里了,所以此时用于标记时间的vis1数组在此点应为0,如果我们把所有方格都初始化为0的话,火所在初始点的标记就比较麻烦,所以统一都初始化为-1,后续两个for循环遍历每个位置,对有火的位置才标记vis1[i][j] = 0,并且把初始点有火的坐标压入到队列,接着就是常规的bfs,利用队列更新vis1数组(火所能烧到的位置的最短时间),直到烧过能烧到的方格为止。
同理,求人在逃出迷宫时所用的最短时间也是bfs的思想,bfs函数中也是常规的做法,利用队列实现vis2数组的更新(人所能到达的位置的最短时间),只不过在坐标node是否能压入队列的判断条件中还多了判断在人到达这个方格之前火有没有烧到过,当坐标已经到达迷宫边界的时候,返回vis[i][j] + 1;若队列已经为空,人还没走到迷宫边界,则返回-1(代表人走不出迷宫了)。
这道题需要注意的地方:
在判断人到达某个方格时,火烧到过这个方格的判断条件应该是vis2[n.x][n.y] + 1 >= vis1[p][q] && vis1[p][q] != -1,vis1[p][q] != -1这个不能省略,我们已知vis1[p][q]的初始化为-1,如果在bfs1函数中vis1[p][q]没被更新过,则说明火根本没烧过这个方格,而此时人到了这个方格,vis2[n.x][n.y] + 1必定大于-1,此时判断条件是成立的,所以这个点会被误认为是人不能到达的,从而执行了continue,所以要&& vis1[p][q] != -1,代表此方格在人到达之前已经被火烧过,即人不能到达此方格。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int r, c, i, j, p, q, p1, q1;
char a[1005][1005];
int vis1[1005][1005], vis2[1005][1005]; //vis1数组代表火烧到这个方格所用的最短时间,vis2数组代表人走到这个方格所用的最短时间
int b[4][2] = {
{
0, 1}, {
0, -1}, {
1, 0}, {
-1, 0}}