UVA11624

4 篇文章 0 订阅
3 篇文章 0 订阅


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 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 Specification

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.

Sample Input

2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F

Output Specification

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.

Output for Sample Input

3
IMPOSSIBLE
 
 
分析:其实这道题目不难,只是加了一个fire的状态。所以在用bfs搜索之前需要先找到每个点的最早着火时间,这个过程也是一个bfs的搜索过程。这里要注意的就是开始的时候可能有不止一个火源,所以某个位置最早从哪个时刻开始着火会受到多个火源的影响,于是开始的时候要将所有的火源都放到队列中才开始进行第一次的着火时间搜索。至于为什么要在开始的时候将所有的火源都放到队列中,根据《算法导论》书的P347的引理22.3知道这样能够找出每个点的最早着火时间。而不必每次找到一个火源就急着开始搜索其它点的着火时间,之后再根据其它火源到该点的着火时间进行更新,后者是会造成TLE的。最后再结合每个点的最早着火时间和迷宫路径进行第二次的bfs搜索。
 
#include<iostream>
#include<string.h>
#include<queue>
#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<<ans<<endl;
        else
            cout<<"IMPOSSIBLE"<<endl;
    }
    return 0;
}


int bfs(int R, int C)
{
    queue<Point> 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<Point> 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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值