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.
2 4 4 #### #JF# #..# #..# 3 3 ### #J. #.F
3 IMPOSSIBLE
分析:其实这道题目不难,只是加了一个fire的状态。所以在用bfs搜索之前需要先找到每个点的最早着火时间,这个过程也是一个bfs的搜索过程。这里要注意的就是开始的时候可能有不止一个火源,所以某个位置最早从哪个时刻开始着火会受到多个火源的影响,于是开始的时候要将所有的火源都放到队列中才开始进行第一次的着火时间搜索。至于为什么要在开始的时候将所有的火源都放到队列中,根据《算法导论》书的P347的引理22.3知道这样能够找出每个点的最早着火时间。而不必每次找到一个火源就急着开始搜索其它点的着火时间,之后再根据其它火源到该点的着火时间进行更新,后者是会造成TLE的。最后再结合每个点的最早着火时间和迷宫路径进行第二次的bfs搜索。
#include
#include
#include
#define INF 10001
using namespace std;
typedef struct{
int x, y;
}Point;//定义一个结构体用来表示坐标点
int bfs(int R, int C);
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};//用来表示朝四个方向移动
int FirTime[1005][1005];//用这个数组来记录该坐标点什么时候会有火势蔓延过来
int GetTime[1005][1005];
char maze[1005][1005];
int main()
{
int ncase;
int R, C;
cin>>ncase;
while(ncase--){
cin>>R>>C;
for(int i = 0; i < R; i++)
cin>>maze[i];//input the information of maze
int ans = bfs(R, C);
if(ans > 0)
cout< q1;
for(int i = 0; i < R; i++)
for(int j = 0; j < C; j++)
FirTime[i][j] = INF;//初始化FirTime
for(int i = 0; i < R; i++){
for(int j = 0; j < C; j++){
if(maze[i][j] == 'F'){
Point p; p.x = i, p.y = j;//首先通过外面的两层循环找到其中的火源
FirTime[i][j] = 0;
q1.push(p);//把火源点放入到队列中y
}
}
}
while(!q1.empty()){//当队列不空时
Point temp = q1.front();//把头部的元素取出
q1.pop();
for(int m = 0; m < 4; m++){//向四周扩展
int xx = temp.x + dx[m];
int yy = temp.y + dy[m];
//首先要在maze中,然后不能是栅栏
if(xx >= 0 && xx < R && yy >= 0 && yy < C && maze[xx][yy] != '#' && (FirTime[xx][yy] > FirTime[temp.x][temp.y] + 1)){//如果下一个可能移动到的点的FireTime太大了咋没有必要将其放入队列中
Point next; next.x = xx; next.y = yy;
FirTime[xx][yy] = FirTime[temp.x][temp.y] + 1;
q1.push(next);//把这个点放进去并且改变这个点的FirTime的值
}//if
}//for
}//while
queue q2;
int Jx, Jy;
Point J;
for(int i = 0; i < R; i++)
for(int j = 0; j < C; j++)
GetTime[i][j] = -1;//首先对GetTime进行初始化
for(int i = 0; i < R; i++)//首先找到Joe开始的时候所在的位置,并且将GetTime至为0
for(int j = 0; j < C; j++)
if(maze[i][j] == 'J'){
Jx = i; Jy = j;
J.x = Jx; J.y = Jy;
GetTime[i][j] = 0;
goto loop;
}
loop: q2.push(J);//把Joe点的坐标放入到队列中
while(!q2.empty()){
Point temp = q2.front();//取出对头的元素
q2.pop();//将对头的元素弹出y
for(int i = 0; i < 4; i++){
int xx = temp.x + dx[i];
int yy = temp.y + dy[i];
if(xx < 0 || xx >= R || yy < 0 || yy >= C){//如果已经走出了maze则返回那个最小的值
while(!q2.empty())
q2.pop();
return GetTime[temp.x][temp.y] + 1;
}
if(maze[xx][yy] != '#' && (GetTime[xx][yy] == -1) && FirTime[xx][yy] > (GetTime[temp.x][temp.y] + 1)){
Point next;
next.x = xx; next.y = yy;
q2.push(next); GetTime[xx][yy] = GetTime[temp.x][temp.y] + 1;
}
}//for
}//while
return -1;
}