码迷,mamicode.com
首页 > 其他好文 > 详细

Fire! -两次dfs

时间:2019-02-10 20:43:44      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:initial   地方   tin   put   family   结构   margin   output   start.s   

题目描述:

Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the maze neglected to create a fire escape plan. Help Joe escape the maze. Given Joe’s location in the maze and which squares of the maze are on fire, you must determine whether Joe can exit the maze before the fire reaches him, and how fast he can do it. Joe and the fire each move one square per minute, vertically or horizontally (not diagonally). The fire spreads all four directions from each square that is on fire. Joe may exit the maze from any square that borders the edge of the maze. Neither Joe nor the fire may enter a square that is occupied by a wall.

Input

The first line of input contains a single integer, the number of test cases to follow. The first line of each test case contains the two integers R and C, separated by spaces, with 1 ≤ R, C ≤ 1000. The following R lines of the test case each contain one row of the maze. Each of these lines contains exactly C characters, and each of these characters is one of: ? #, a wall ? ., a passable square ? J, Joe’s initial position in the maze, which is a passable square ? F, a square that is on fire There will be exactly one J in each test case.

Output

For each test case, output a single line containing ‘IMPOSSIBLE’ if Joe cannot exit the maze before the fire reaches him, or an integer giving the earliest time Joe can safely exit the maze, in minutes.

Sample Input

2

4 4

####

#JF#

#..#

#..#

3 3

###

#J.

#.F

Sample Output

3

IMPOSSIBLE

题意:Joe要逃离一个迷宫,迷宫中有地方起火了,在火开始燃烧的时候Joe也开始逃,火的蔓延方式与Joe的行动方式一样,都是1个单位时间可以往上下左右四个方向各走一格。另外,迷宫内有墙,Joe与火都无法穿墙。现在给你一个图,请问Joe能否从迷宫的边界处逃出而不被火烧到,如果能的话请输出最短的逃脱时间,不能的话输出“IMPOSSIBLE”。其中,‘F’代表火,‘J’代表Joe,‘#’代表墙。

解题思路:参考博客 https://blog.csdn.net/JZQT_T/article/details/38641127

这题首先注意的就是,起火点可能不止一个,也可能没有起火点。其次是如果一个起火点被四周的墙给封闭起来了,那么这个火就相当于没有用了。为了判断Joe走到某个点时这个点是否已经起火,我们需要知道每个点起火的时间。其实可以把每个初始起火点当成一个起火点的邻节点加入队列,这样就只进行了一次BFS,从而获得了每个点起火的时间(如果有些点不会起火,那么这些点的时间就是初始化的INF)。最后从Joe的起点开始BFS一次,如果走到下一个点时那个点已经或者刚好着火了那就不能走,墙也不能走,只要走到边界就说明可以走出迷宫了。

代码:

  1 //直接预处理出火烧到每一个格子的时间,bfsbfs的时候,已经有火在烧的格子和墙一样处理就行了,火烧时间的预处理也用bfsbfs就行
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <queue>
  7 
  8 using namespace std;
  9 
 10 #define N 1001
 11 #define INF 999999999
 12 
 13 struct point        //定义点结构体
 14 {
 15     int x, y;   //坐标
 16     int step;   //步数,相当于时间
 17 };
 18 
 19 int dx[] = {1, -1, 0, 0};   //方向向量
 20 int dy[] = {0, 0, -1, 1};   //方向向量
 21 
 22 int n, m, t;
 23 char map[N][N];
 24 int vis[N][N];          //记录火或者人到达点花费的最少时间
 25 point start, fire;      //起点和起火处
 26 queue <point> q;
 27 
 28 void FireBfs()
 29 {
 30     point a, b;
 31     while (!q.empty())
 32     {
 33         a = q.front();
 34         q.pop();
 35         for (int j=0; j<4; ++j)
 36         {
 37             int nx = a.x + dx[j];
 38             int ny = a.y + dy[j];
 39             if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;       //越界
 40             if (map[nx][ny] == # || vis[nx][ny] <= a.step + 1) continue;  //墙或者已经走过的点
 41             b.x = nx;
 42             b.y = ny;
 43             //走到这一格的时间=火烧到这一格的时间=上一格的步数加1
 44             b.step = vis[nx][ny] = a.step + 1;
 45             q.push(b);
 46         }
 47     }
 48     return;
 49 }
 50 
 51 void DataProcess()
 52 {
 53     point a, b;
 54     FireBfs();
 55     q.push(start);      //将人的起点加入队列准备Bfs
 56     while (!q.empty())
 57     {
 58         a = q.front();
 59         q.pop();
 60         for (int i=0; i<4; ++i)
 61         {
 62             int nx = a.x + dx[i];
 63             int ny = a.y + dy[i];
 64             if (nx < 0 || nx >= n || ny < 0 || ny >= m)     //成功走到边界
 65             {
 66                 printf("%d\n", a.step + 1);
 67                 return;
 68             }
 69             if (map[nx][ny] == # || vis[nx][ny] <= a.step + 1) continue;  //遇到墙或者该点起火或者走过
 70             b.x = nx;
 71             b.y = ny;
 72             b.step = vis[nx][ny] = a.step + 1;//走到这一步的时间=火烧到这一格的时间=上一格的步数加1
 73             q.push(b);
 74         }
 75     }
 76     puts("IMPOSSIBLE");
 77     return;
 78 }
 79 
 80 int main()
 81 {
 82     scanf("%d", &t);
 83     while (t--)
 84     {
 85         scanf("%d %d", &n, &m);
 86         for (int i=0; i<n; ++i)
 87         {
 88             scanf("%s", map[i]);
 89         }
 90         while (!q.empty()) q.pop();     //清空队列
 91         for (int i=0; i<n; ++i)
 92         {
 93             for (int j=0; j<m; ++j)
 94             {
 95                 vis[i][j] = INF;        //初始vis
 96                 if (map[i][j] == J)
 97                 {
 98                     start.x = i;
 99                     start.y = j;
100                     start.step = 0;
101                     vis[i][j] = 0;
102                 }
103                 else if (map[i][j] == F)
104                 {
105                     fire.x = i;
106                     fire.y = j;
107                     fire.step = 0;
108                     q.push(fire);           //加入队列准备进行火的Bfs
109                     vis[i][j] = 0;
110                 }
111             }
112         }
113         DataProcess();
114     }
115     return 0;
116 }

Fire! -两次dfs

标签:initial   地方   tin   put   family   结构   margin   output   start.s   

原文地址:https://www.cnblogs.com/LJHAHA/p/10360084.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!