kuangbin专题一 简单搜索 起火迷宫(UVA-11624)

发布时间 2023-04-15 20:15:47作者: Amαdeus

Fire!

Description

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 orhorizontally (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


题目大意

给定一个矩阵,矩阵中有一个 'J' 代表约翰,若干个 'F' 代表火,'#' 代表墙,'.' 代表通路。火每过一分钟会向上、下、左、右四个方向蔓延,当然火无法穿过墙壁。约翰每次可以向上、下、左、右四个方向移动,每次只能移动一步且消耗一分钟。求约翰到达任意边界处的最短时间,约翰无法走到被火占据的地方,当然约翰也无法穿墙,因为他不是霍青娥。如果可以到达边界处,输出最短时间;若不可以,则输出 IMPOSSIBLE 。



解题思路

由于题目中有两种会变化的东西,一个是约翰,一个是若干个火源,同时对两者进行BFS,是比较麻烦的。所以可以先以火为变量,进行多源BFS,求出方格被火占据的时刻,然后再对以约翰为变量进行BFS求最短路,与常规BFS求最短路模型不同的是,需要多加一个是否下一步会走到火上的判断,其它地方也都和BFS模板差不多。不过需要注意的是,在初始化dist数组时,需要初始化为 inf,原因之一在判断是否下一步会走到火上时,用的是大于等于的关系,火无法穿墙,有些地方火是走不到的,而约翰是可以走到的,如果全部初始化为-1,这个火无法走到的地方的dist一直为-1,那么在此时判断会出现错误。

/*   一切都是命运石之门的选择  El Psy Kongroo  */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
typedef pair<double, double> pdd;
typedef pair<string, pii> psi;
typedef __int128 int128;
#define PI acos(-1.0)
#define x first
#define y second
const int inf = 0x3f3f3f3f, mod = 1e9 + 7;

const int N = 1010;
char g[N][N];
int n, m, sx, sy;
int dist_p[N][N], dist_f[N][N];
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

//火 多源BFS
void bfs_f(queue<pii> q){
    while(!q.empty()){
        auto [x, y] = q.front();
        q.pop();

        for(int k = 0; k < 4; k ++ ){
            int nx = x + dx[k], ny = y + dy[k];
            if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if(g[nx][ny] == '#' || dist_f[nx][ny] != inf) continue;

            q.push(make_pair(nx, ny));
            dist_f[nx][ny] = dist_f[x][y] + 1;
        }
    }
}

//人 BFS求最短路
int bfs_p(){
    if(sx == 0 || sx == n - 1 || sy == 0 || sy == m - 1) return 0;
    queue<pii> q; q.push(make_pair(sx, sy));
    dist_p[sx][sy] = 0;

    while(!q.empty()){
        auto [x, y] = q.front();
        q.pop();

        for(int k = 0; k < 4; k ++ ){
            int nx = x + dx[k], ny = y + dy[k];
            if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;  //出界
            if(g[nx][ny] == '#' || dist_p[nx][ny] != inf) continue; //无法到达 或 已经访问过
            if(dist_p[x][y] + 1 >= dist_f[nx][ny]) continue;      //此时已经被火占据

            q.push(make_pair(nx, ny));
            dist_p[nx][ny] = dist_p[x][y] + 1;

            if(nx == 0 || ny == 0 || nx == n - 1 || ny == m - 1)
                return dist_p[nx][ny];  //到达边界处
        }
    }

    return -1;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T; cin >> T;
    while(T -- ){
        cin >> n >> m;
        memset(dist_f, 0x3f, sizeof(dist_f));    //注意 需要初始化为inf 不然在比较d_p与d_f时会导致错误
        memset(dist_p, 0x3f, sizeof(dist_p));
        queue<pii> fire;
        for(int i = 0; i < n; i ++ )
            for(int j = 0; j < m; j ++ ){
                cin >> g[i][j];
                if(g[i][j] == 'J') sx = i, sy = j;  //起点
                if(g[i][j] == 'F') fire.push(make_pair(i, j)), dist_f[i][j] = 0; //火入队 进行多源BFS
            }

        bfs_f(fire);

        int res = bfs_p();
        if(res == -1) cout << "IMPOSSIBLE" << endl;
        else cout << res + 1 << endl;
    }

    return 0;
}