BFS——1072 Nightmare

1072 Nightmare

请添加图片描述

文章目录


题意:

小明被困在一个迷宫如下中:
1.小明每次可以花一个单位时间往上下左右的某个方向移动一格。
2.小明身上有一个炸弹,在第6个单位时间就会爆炸,在第6个单位时间走到终点或者刷新炸弹时间是无效的。

举例如下:
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
0. 障 碍 {\color{red}0.障碍} 0.
1. 平 路 {\color{red}1.平路} 1.
2. 起 点 {\color{red}2.起点} 2.
3. 终 点 {\color{red}3.终点} 3.
4. 可 以 刷 新 炸 弹 时 间 {\color{red}4.可以刷新炸弹时间} 4.

思路:

只需要在bfs的基础上修改标记数组即可:

bfs为了避免重复搜索,一般将某个坐标定义为一个状态:
一般的,如果我们搜索过 ( x , y ) (x,y) (x,y),我们下次再次搜索到这个点时将不会把这个点再次加入队列中。

但是这题中,我们的状态应该多加一个走到该点时的炸弹时间:

即我们认为 ( x , y , 0 ) ( 当 前 炸 弹 在 第 0 个 单 位 时 间 ) (x,y,0)(当前炸弹在第0个单位时间) (x,y,0)(0) ( x , y , 1 ) ( 当 前 炸 弹 在 第 1 个 单 位 时 间 ) (x,y,1)(当前炸弹在第1个单位时间) (x,y,1)(1)等是不同的状态,所以我们在炸弹时间不同的情况下,一个点可能可以重复入队。

不妨举一个显然的例子:
2 1 1 1 4
1 0 0 0 1
1 0 4 1 1
1 0 1 0 0
1 1 1 1 3

标记数组处理如下:

bool book[N][N]->bool book[N][N][7]

时间复杂度:

O ( n ∗ m ) O(n*m) O(nm)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 20,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;
struct Node{
    int x,y,step,time;
}que[N*N*6];
int g[N][N];
int ne[4][2] = {0,1,1,0,-1,0,0,-1};
bool book[N][N][7];
int n,m,start_x,start_y,end_x,end_y;

bool OK(int x,int y,int t)
{
    if(x<1||y<1||x>n||y>m||g[x][y]==0||book[x][y][t])return false;
    return true;
}

int bfs()
{
    int tail = -1,head = 0;
    que[++tail] = {start_x,start_y,0,0};
    book[start_x][start_y][0] = true;
    while(tail>=head)
    {
        auto temp = que[head++];
        if(temp.x==end_x&&temp.y==end_y)return temp.step;
        if(temp.time==5)continue;//炸弹时间在5其实已经无法拓展
        for(int i = 0 ; i < 4 ; i++)
        {
            int tx = ne[i][0] + temp.x;
            int ty = ne[i][1] + temp.y;
            if(g[tx][ty]==4)
            {
                if(OK(tx,ty,0))
                    que[++tail] = {tx,ty,temp.step+1,0},book[tx][ty][0] = true;
            }
            else
            {
                if(OK(tx,ty,temp.time+1))
                    que[++tail] = {tx,ty,temp.step+1,temp.time+1},book[tx][ty][temp.time+1] = true;
            }
        }
    }
    return -1;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        memset(book,false,sizeof book);
        std::cin>>n>>m;
        for(int i = 1 ; i <= n ; i++)
        {
            for(int j = 1 ; j <= m ; j++)
            {
                std::cin>>g[i][j];
                if(g[i][j]==2)
                {
                    start_x = i,start_y = j;
                }
                else if(g[i][j]==3)
                {
                    end_x = i,end_y = j;
                }
            }
        }
        std::cout<<bfs()<<'\n';
    }
    return 0;
}




  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值