Nightmare

博客讲述了Ignatius在迷宫中带着定时炸弹逃生的问题。炸弹初始爆炸时间为6分钟,迷宫中有重置装置可将时间重置。这是一个简单广搜题,需注意特殊点‘4’,抵达该点炸弹时间会重置,解题时只需标记此点。

Nightmare

Ignatius had a nightmare last night. He found himself in a labyrinth with a time bomb on him. The labyrinth has an exit, Ignatius should get out of the labyrinth before the bomb explodes. The initial exploding time of the bomb is set to 6 minutes. To prevent the bomb from exploding by shake, Ignatius had to move slowly, that is to move from one area to the nearest area(that is, if Ignatius stands on (x,y) now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the next minute) takes him 1 minute. Some area in the labyrinth contains a Bomb-Reset-Equipment. They could reset the exploding time to 6 minutes.

Given the layout of the labyrinth and Ignatius’ start position, please tell Ignatius whether he could get out of the labyrinth, if he could, output the minimum time that he has to use to find the exit of the labyrinth, else output -1.

Here are some rules:

  1. We can assume the labyrinth is a 2 array.
  2. Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk on a wall, too.
  3. If Ignatius get to the exit when the exploding time turns to 0, he can’t get out of the labyrinth.
  4. If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can’t use the equipment to reset the bomb.
  5. A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many times as you wish.
  6. The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the exploding time is larger than 0, the exploding time would be reset to 6.

输入:

3
3 3
2 1 1
1 1 0
1 1 3
4 8
2 1 1 0 1 1 1 0
1 0 4 1 1 0 4 1
1 0 0 0 0 0 0 1
1 1 1 4 1 1 1 3
5 8
1 2 1 1 1 1 1 4 
1 0 0 0 1 0 0 1 
1 4 1 0 1 1 0 1 
1 0 0 0 0 3 0 1 
1 1 4 1 1 1 1 1 

输出:

4
-1
13

思路:

这是一个简单的广搜题,需要注意的就是’4’这个特殊点,抵达这个点的时候炸弹时间会重置为6,有时候在直走到不了终点的时候,拐弯走一下’4’这个点然后回来便可抵达终点,所以这道题只需要标记’4’这一个点就行(刚开始写并没有标记’4’,导致不出结果改了好久 )。

代码

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
struct Inof
{
    int x;
    int y;
    int step;   //储存步数
    int d;     //用来储存剩余时间
    friend operator < ( Inof a,Inof b)   //设定优先级,步数小的优先出列
    {
        return a.step > b.step;
    }
};
int N,M;
bool vis[300][300];
int cx,cy,ex,ey;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
char map[300][300];
bool panding(int x,int y)   //判定这个点是否可以走
{
    if(x<1||y<1||x>N||y>M)
        return 1;
    if(vis[x][y])
        return 1;
    if(map[x][y]=='0')
        return 1;
    return 0;
}
void fin()
{
    memset(vis,0,sizeof(vis));  //初始化布尔数组
}
int bfs()
{
    priority_queue<Inof> a;
    Inof cur,next;
    cur.x=cx;
    cur.y=cy;
    cur.step=0;
    cur.d=6;
    a.push(cur);   //第一个元素入列
    while(!a.empty())
    {
        cur = a.top();
        a.pop();
        if(cur.d<1)   //这里是一个关键,如果剩余时间小于1,那么抵达终点也离不开迷宫
            continue;
        if(cur.x==ex&&cur.y==ey)   //抵达终点返回最小步数
        {
            return cur.step;
        }
        for(int i=0;i<4;i++)   //广搜开始
        {
            int x=cur.x+dx[i];
            int y=cur.y+dy[i];
        //判断是否可以走,如果剩余时间为1,无论下一步抵达'4'还是终点都无济于事,所以舍弃
            if(panding(x,y)||cur.d<=1)
                continue;
            next.x=x;
            next.y=y;
            next.step=cur.step+1;
            if(map[x][y]=='4')  //如果抵达的点是'4'则时间重置,并标记此点
            {
               next.d=6;
               vis[x][y]=1;
            }
            else
                next.d = cur.d-1;
            a.push(next);   //新元素入列
        }
    }
    return -1;   //如果所有可抵达点都已遍序依然没有到达终点返回-1(题设要求)
}
int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        cin >> N >> M;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)
        {
            cin >> map[i][j];
            if(map[i][j]=='2')  //记录入口
                cx=i,cy=j;
            if(map[i][j]=='3')
                ex=i,ey=j;    //记录出口
        }
        fin();
        int t = bfs();
        cout << t << endl;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值