Fire! -两次dfs

题目描述:

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 }

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

时间: 2024-10-30 14:03:49

Fire! -两次dfs的相关文章

hdoj 1045 Fire Net 【DFS】

题意:如果两个点要放在同一行或者同一列,那么两个点中间要有一个墙,否则的话只能放一个点,最后问你最多能放几个点. 看了一个星期.. 这道题的解法我还是第一次见,就是逐个逐个的来放置每个点,然后每经过一个点都判断一次,详情看代码 代码: #include <stdio.h> #include <string.h> int ans, n; char map[10][10]; int judge(int lin, int row) { int i; for(i = lin-1; i &g

蓝桥杯 大臣的旅费_树的最长度_两次DFS

#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <functional> #include <vector> using namespace std; const int maxn = 1000000 + 10; const int INF = 10000000

【2-SAT(两次DFS版)】BZOJ1823-[JSOI2010]满汉全席

[题目大意] 有n个材料,m个评委.每种材料可以被用来做满族菜或汉族菜,m个评委有两种可以让他满意的猜中.问是否可以满足所有评委要求? [思路] 每天只能做三道题,我已经是一个废人了……(葛平躺.jpg) 裸2-SAT,先写了个两遍DFS的,速度略慢……24ms? 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<ve

HDU1045 Fire Net 【DFS】

Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6285    Accepted Submission(s): 3552 Problem Description Suppose that we have a square city with straight streets. A map of a city is a

蒟蒻浅谈树链剖分之一——两个dfs操作

树链剖分,顾名思义就是将树形的结构剖分成链,我们以此便于在链上操作 首先我们需要明白在树链剖分中的一些概念 重儿子:某节点所有儿子中子树最多的儿子 重链:有重儿子构成的链 dfs序:按重儿子优先遍历时的顺序 轻儿子的意思就与重儿子相反 首先是第一个dfs操作 在本次操作中,我们主要做的是处理所有节点的父亲,子树大小,重儿子,深度等操作 void dfs1(int now,int father,int deep) { tree[now].depth=deep;//初始化当前节点的深度,子树大小,父

黑科技——树剖两次dfs转一次dfs!

黑科技--树剖两次\(dfs\)转一次\(dfs\)! 重所周知,树链剖分通常是要\(dfs?\)两次的,就像这样: int Fa[N],dep[N],Sz[N],son[N]; void dfs1(int x,int pre){ Fa[x]=pre,dep[x]=dep[pre]+1; Sz[x]=1; erep(i,G,x){ int y=G.to[i]; if(y==pre)continue; dfs(y,x); Sz[x]+=Sz[y]; (Sz[y]>Sz[son[x]])&&am

FZOJ 2150 Fire Game (DFS + BFS)

题目链接:Fire Game 题意:一块n*m的矩形中,'#'代表是草,'.'代表空地,空地点不着火.两个人同时开始点火,问最短多少时间能把所有草地点着,不能输出'-1'. 解析:先用dfs预判断草地的连通块数,超过2则无法全部点燃 任选两个草地作起点,两者看作是一个整体,用bfs搜到起点到所有草地的最短时间,然后保留其中最长的时间 在所有的最长时间中,选择最短的,即为所求. AC代码: #include <cstdio> #include <cstring> #include &

HDU 1045 Fire Net(dfs,跟8皇后问题很相似)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 14670    Accepted Submission(s): 8861 Problem Description Suppose that we have a squar

uva11624 - Fire! 两次bfs

题目链接 Problem B: Fire! 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