E - Fire! UVA - 11624(bfs + 记录火到达某个位置所需要的最小时间)

E - Fire! UVA - 11624

题目描述
乔在迷宫中工作。不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划。请帮助乔逃离迷宫。根据乔在迷宫中的位置以及迷宫的哪个方块着火,你必须确定火焰烧到他之前,乔是否可以离开迷宫,如果能离开他能跑多快。
乔和火每分钟移动一个方格,上、下、左、右,四个方向中的一个。火势向四个方向同时蔓延。乔可以从迷宫的任何一个边界逃离迷宫。无论是乔还是火都不会到达有墙的位置。
输入 第一行输入包含一个整数,即测试次数 每个测试用例的第一行包含两个 整数R和C,用空格分隔,1≤R,C≤1000
下面R行中,每一行都包含C个字符,以及每个字符是以下之一:
#代表墙 . 代表空地,火和乔是可通行的 J 乔在迷宫中最初的位置,火和乔是可通行的 F 代表火 在每组测试中只有一个J 输出 对于每个测试用例,如果在火蔓延的时候烧到了乔,则乔无法逃出迷宫,输出’IMPOSSIBLE’如果乔能逃出迷宫,则输出乔最快可以在几分钟内安全逃出迷宫,每组输出占一行

####
#JF#
#..#
#..# 3 3
###
#J.
#.F 样例输出 
3
IMPOSSIBLE

思路如下

  • 题意:有 好多堆 🔥,问能不能在火烧到人之间,顺利逃出迷宫
  • 思路:我们可以用一个专门的书组统计 🔥 到达某个位置所需的最短时间,但是我们会想可能有 好多堆 🔥,那么怎对 🔥 应用编写一个bfs_fire() 呢? ,其实应用 也很简单,就是一次性把所有 🔥 的初始位置全部压入 队列 q,就行了,然后在不断更新 🔥 到达某个位置所需的最小时间(具体看代码);然后我们可以考虑对 “🏃人” 编写一个bfs_man(),有一个地方需要理解就是 : 人怎么才能安全的到达某个位置 ???,显然 人到达该位置的时间只要 小于所有🔥到达该位置所需的最小时间,就可安全到达该位置,而“所有🔥到达该位置所需的最小时间”已经在调用 bfs_fire() 的时候被计算出来了,最后再补充:人只要赶在🔥之前先到达边界就可以安全逃生了 。————(剩下不懂的具体看代码吧)

题解如下

wa了十几发终于做出来了在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>

using namespace std;

const int Len = 1005;
char map[Len][Len];
int mov[4][2] = { {1,0},{0,1},{-1,0},{0,-1}};
int tim[Len][Len];      //火到达(i , j)位置所需要最短的时间是 tim[i][j]
int mark[Len][Len];     //标记人是否走过某个位置
vector<pair<int , int > > pir;  //pir用来存储所有🔥初始位置的坐标
int m,n;
int x,y;    /* 人的坐标 */
struct Node
{
    int x,y,t;
}st,ed;
queue<Node> q;

//火专用
void bfs_fire()
{
    //初始化
    for(int i = 0; i < m; i ++)
        for(int j = 0; j < n; j ++)
            tim[i][j] = 1e9;
    while(pir.size() > 0)           //把所有🔥的初始位置压入队列进行处理
    {
        st.x = pir.back().first;
        st.y = pir.back().second;
        st.t = 0;
        tim[st.x][st.y] = 0;
        q.push(st);
        pir.pop_back();
    }
    while(! q.empty())
    {
        st = q.front();
        q.pop();

        for(int i = 0; i < 4; i ++)
        {
            ed.x = st.x + mov[i][0];
            ed.y = st.y + mov[i][1];
            ed.t = st.t + 1;
            if(ed.x >= 0 && ed.y >= 0 && ed.x < m && ed.y < n && map[ed.x][ed.y] != '#' && tim[ed.x][ed.y] > ed.t)
            {
                tim[ed.x][ed.y] = ed.t;         //更改到达(ed.x , ed.y)位置所需要的最小时间为:ed.t;
                q.push(ed);
            }
        }
    }
}

int min_time;
//人专用
bool bfs_man()
{
    bool flag = 0;
    //各种初始化、赋值、做标记、压队列
    min_time = 1e9;
    memset(mark , 0 , sizeof(mark));
    st.x = x;
    st.y = y;
    st.t = 0;
    mark[st.x][st.y] = 1;
    q.push(st);
    while(! q.empty())
    {
        st = q.front();
        q.pop();
        if(st.x == 0 || st.y == 0 || st.x == m - 1 || st.y == n - 1)
        {
            flag = 1;
            min_time = min(min_time , st.t);
            continue;
        }

        for(int i = 0; i < 4; i ++)
        {
            ed.x = st.x + mov[i][0];
            ed.y = st.y + mov[i][1];
            ed.t = st.t + 1;
            if(ed.x >= 0 && ed.y >= 0 && ed.x < m && ed.y < n && map[ed.x][ed.y] != '#' && mark[ed.x][ed.y] == 0 && ed.t < tim[ed.x][ed.y])         /* ed.t < tim[ed.x][ed.y] 表明 人到达(ed.x , ed.y) 所需时间ed.t 只有小于🔥到达该位置所需要的最小时间tim[ed.x][ed.y] 人才可以安全的走到这个位置 */
            {
                mark[ed.x][ed.y] = 1;
                q.push(ed);
            }
        }
    }
    return flag;
}

int main()
{
    //freopen("test.txt","r",stdin);
    int t;
    scanf("%d", &t);
    while(t --)
    {
        scanf("%d %d ", &m, &n);
        pair<int , int> pirr;
        for(int i = 0; i < m; i ++)
        {
            for(int j = 0; j < n; j ++)
            {
                scanf("%c", &map[i][j]);
                if(map[i][j] == 'J')
                {
                    x = i,y = j;
                }
                else if(map[i][j] == 'F')
                {
                    pirr.first = i;
                    pirr.second = j;
                    pir.push_back(pirr);
                }
            }
            getchar();
        }

        bfs_fire();
        if(bfs_man())
        {
            printf("%d\n",min_time + 1);
        }
        else
            printf("IMPOSSIBLE\n");
    }

    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值