I - Fire UVA - 11624

版权声明:本文为博主原创文章,未经博主允许不得转载。若有误,欢迎私信指教~ https://blog.csdn.net/little_starfish/article/details/79235356

Background:
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

题目大意:一个人在R * C大小的迷宫里,问能不能成功逃离,能则输出最少的步数,否则输出“IMPOSSIBLE”。迷宫里面有火堆(我不确定后台数据有是不是只有一堆火,所以按照可能有多堆火做的,其实跟只有一堆火的做法几乎一样,就是在找火堆坐标的预处理时有不同)。人的初始位置用J表示,火堆用F,墙用#,正常的可走的路用.表示。
注意:墙的方格人不能走,火也不能烧。人和火堆都是每个时间单位可以向上下左右四个方向移动一格。另外,当人成功到达边界时,步数要 + 1,才算逃离迷宫。(人不能走有火的地方)

Think: 中等难度的广度优先搜索(BFS)。在BFS时要先对火堆,在对人,看两组样例就明白了。这题有一个小坑点,加入一开始人就在迷宫边界,则直接步数 == 1。
一开始WA了好几发,之前都是一个一个地从一个点往外扩,这题不行,需要对步数相同的点同时向四周扩一遍(人和火堆都是这样,不然就要另外增加变量什么的,判断步数大小(即时间先后-顺序-是人先到达的某个位置,还是火堆));

之前几乎一直用纯C敲的代码,没用C++里的,渐渐地发现还是C++方便…
C++代码如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef struct node  //存人的点的结构体
{
    int x;  //横坐标
    int y;  //纵坐标
    int step;  //步数
} node;
typedef struct no  //存火堆的点的结构体
{
    int x;
    int y;
} no;
no p[10000010];  //模拟队列
node que[10000010];  //模拟队列
int next1[4] = {-1, 1, 0, 0};  //为了方便循环跑上下左右四个方向的数组
int next2[4] = {0, 0, -1, 1};
int n, m;  //地图大小
int he, to;  //为了方便对初始火堆的处理的栈顶、底,数组模拟
char s[1005][1005];  //地图
bool bb[1005][1005];  //布尔类型,只有0、1两种值(Windows系统是这样)
bool bbb[1005][1005];  //bb是标记人走过的点,bbb是火堆走过的点
void BFS(int a, int b);  //广搜
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &n, &m);
        memset(bb, 0, sizeof(bb));  初始化值为0
        memset(bbb, 0, sizeof(bbb));
        memset(que, 0, sizeof(que));
        memset(p, 0, sizeof(p));
        he = 1;
        to = 1;
        int i, j;
        int a, b;
        for(i = 0; i < n; i++)
        {
            scanf("%s", s[i]);
            for(j = 0; j < m; j++)
            {
                if(s[i][j] == 'J')  //寻找人
                {
                    a = i;
                    b = j;
                }
                if(s[i][j] == 'F')  //初始火堆的位置
                {
                    p[to].x = i;
                    p[to].y = j;
                    bbb[i][j] = 1;
                    to++;
                }
            }
        }
        if(a == 0||a == n - 1||b == 0||b == m - 1)  //如果一开始人在边界
        {
            printf("1\n");
        }
        else BFS(a, b);  //广搜
    }
    return 0;
}
void BFS(int a, int b)
{
    int head = 1, top = 1;  //人的点的栈顶、底
    que[head].x = a;
    que[head].y = b;
    que[head].step = 0;
    top++;
    bb[a][b] = 1;  //标记走过
    int i, ii, j;
    int xx, yy;
    while(head < top)  //最外围还是正常的BFS,处理到队列里所有的点
    {
        int hee = he;  //方便同一步数的点都往外扩
        int too = to;  //看下面的代码就清楚了
        for(j = hee; j < too; j++)  //先扩火堆
        {
            no tt = p[j];
            he++;
            for(ii = 0; ii < 4; ii++)
            {
                xx = tt.x + next1[ii];
                yy = tt.y + next2[ii];
                if(xx < 0||xx >= n||yy < 0||yy >= m||s[xx][yy] == '#')
                {
                    continue;  //如果扩的点超出地图或者是墙则继续上面的操作
                }
                if(!bbb[xx][yy])  //如果当前的点没有在队列中,入队
                {
                    bbb[xx][yy] = 1;
                    p[to].x = xx;
                    p[to].y = yy;
                    to++;
                }
            }
        }
        hee = head;  //人--道理同上
        too = top;
        for(j = hee; j < too; j++)
        {
            node t = que[j];
            head++;
            for(i = 0; i < 4; i++)
            {
                xx = t.x + next1[i];
                yy = t.y + next2[i];
                if(xx < 0||xx >= n||yy < 0||yy >= m)
                {
                    continue;
                }
                if(bb[xx][yy]||bbb[xx][yy]||s[xx][yy] != '.')
                {
                    continue;
                }
                bb[xx][yy] = 1;
                if(xx == 0||xx == n - 1||yy == 0||yy == m - 1)
                {
                    printf("%d\n", t.step + 2);  //如果到达边界
                    return ;
                }
                else
                {
                    que[top].x = xx;
                    que[top].y = yy;
                    que[top].step = t.step + 1;
                    top++;
                }
            }
        }
    }
    printf("IMPOSSIBLE\n");
}

猜你喜欢

转载自blog.csdn.net/little_starfish/article/details/79235356
今日推荐