牛客 | C - 跳刀抓人

题目描述

给定一个n×m的地图,地图上各字符含义如下:

  • .表示空地
  • #表示障碍
  • A表示起点
  • B表示终点

规定移动规则如下:

  • 移动:从当前所在格子移动到上下左右相邻的某个.格子, 需要花费1s.
  • 闪烁:使用跳刀装备,花费1s无视障碍跳跃到切比雪夫距离不超过3.格子(即max(|x1x2|,|y1y2|)3)。跳刀在使用后会进入7s冷却时间,跳刀在冷却时不能使用.
  • 跳刀可以无限次使用.
  • 移动或闪烁都不允许离开这个n×m的地图.
  • 允许原地不动, 即如果当且不处于移动过程或闪烁过程中, 可以在当且格子一直停留, 直到下次移动或者使用跳刀.

(题目链接:https://ac.nowcoder.com/acm/contest/29439/C)

数据范围

2n,m100

题解

该题使用分层图主要从状态转移角度考虑,即若要模拟跳刀的使用,需要增加一维状态表示,即以dist[i][j][k]表示到达(i,j)位置且剩余ks可以使用跳刀的点的距离,这样方便状态转移。
具体的状态转移方法是:

  • 如果当前点的时间为0,则可以使用跳刀,跳刀使用规则见题目,使用完跳刀之后该点的t变为7s

  • 不论当前的时间如何,都可以进行普通的对头扩展,注意该题的不同之处在于可以原地不动,时间减少1s

代码

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

using namespace std;

const int N = 110;

int n, m;
int dist[N][N][10];
char a[N][N];

int dx[5] = {-1, 0, 1, 0, 0}, dy[5] = {0, 1, 0, -1, 0};

struct Node{
    int x, y, t;
}st, ed;

void bfs()
{
    memset(dist, 0x3f, sizeof dist);
    dist[st.x][st.y][0] = 0;

    queue<Node> q;
    q.push(st);
    while(q.size()){
        Node t = q.front();
        q.pop();

        int tx = t.x, ty = t.y, tt = t.t;
        for(int i = 0; i < 5; i ++){
            int x = tx + dx[i], y = ty + dy[i], nt = max(0, tt - 1);
            if(x < 1 || x > n || y < 1 || y > m) continue;
            if(dist[x][y][nt] < 0x3f3f3f3f) continue;
            if(a[x][y] == '#') continue;
            dist[x][y][nt] = dist[tx][ty][tt] + 1;
            q.push({x, y, nt});
        }

        if(tt == 0){
            for(int i = -3; i <= 3; i ++){
                for(int j = -3; j <= 3; j ++){
                    int x = tx + i, y = ty + j, nt = 7;
                    if(x < 1 || x > n || y < 1 || y > m) continue;
                    if(a[x][y] == '#') continue;
                    if(dist[x][y][nt] < 0x3f3f3f3f) continue;
                    dist[x][y][nt] = dist[tx][ty][tt] + 1;
                    q.push({x, y, nt});
                }
            }
        }
    }
    return;
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) scanf("%s", a[i] + 1);

    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            if(a[i][j] == 'A') st = {i, j, 0};
            if(a[i][j] == 'B') ed = {i, j, 0};
        }
    }

    bfs();

    int ans = 0x3f3f3f3f;
    for(int i = 0; i <= 7; i ++) ans = min(ans, dist[ed.x][ed.y][i]);
    if(ans == 0x3f3f3f3f) puts("-1");
    else printf("%d\n", ans);

    return 0;
}

posted @   小菜珠的成长之路  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示