竞赛讨论区 > 23486 小A与小B 题解
头像
牛客638303865号
发布于 01-18 22:38 上海
+ 关注

23486 小A与小B 题解

题目分析

题目大意: 在一个 N×M 的网格迷宫中,有两个角色:

  • 小A(起点 'C'):每次移动 1 格,方向为 8 个方向(上下左右+对角线)。
  • 小B(起点 'D'):每次移动 2 格,方向为 4 个方向(上下左右)。

我们需要找到一个网格点,使得两人都能到达,且两人到达该点所需的时间(回合数)的最大值最小。如果无法相遇,输出 "NO"。

这就求网格图上的最短路问题,由于边权固定(每一步代价固定),首选 BFS(广度优先搜索)

但是因为两人的移动规则不同,我们不能简单地双向奔赴搜索,而是采用 "分别求全图距离" 的策略:

第一遍 BFS (小A):。从 'C' 出发,使用 8 方向数组,计算小A到达地图上每一个格子 (i,j) 所需的最少步数,记为 distA[i][j]。

第二遍 BFS (小B)。 从 'D' 出发,使用 4 方向数组,计算小B到达地图上每一个格子 (i,j) 所需的最少步数(注意这里先算距离),记为 distB[i][j]。

接下来枚举相遇点计算时间。遍历地图上的每一个点 (i,j):如果该点是障碍物或者某人无法到达,跳过。小A的时间:TA​=distA[i][j](因为速度是 1)。小B的时间:由于小B一回合走 2 格,如果距离是 1,耗时 1;距离是 2,耗时 1;距离是 3,耗时 2。 公式为:TB​=⌈distB[i][j]/2⌉=(distB[i][j]+1)/2(利用整数除法向下取整的特性)。两人必须都到达才能算相遇,所以当前点汇合时间取决于慢的那个人:Tmeet​=max(TA​,TB​)。

最后在所有合法的汇合点中,取 Tmeet​ 的最小值即为答案。时间复杂度为O(N×M),空间复杂度为O(N×M)。

注意

  • A与B的方向数组不同。A 是 8 方向,B 是 4 方向,写 BFS 时要分开处理。
  • 处理B 的速度时不要在 BFS 过程中直接让 B 跳两格(处理障碍物会很麻烦),而是按走一步算距离,最后在计算时间时除以 2。这样可以正确处理"第一步能不能走"和"第二步能不能走"的逻辑。
  • 相遇逻辑不是相加除以 2,而是取最大值 max,因为先到的人可以在原地等后到的人。

AC代码

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

int N, M;
char a[1005][1005]; 
int dx[8]={0,1,1,1,0,-1,-1,-1}, dy[8]={1,1,0,-1,-1,-1,0,1};
struct Node {
    int x, y;
};
int dist[1005][1005]; 
int bfs(int sx, int sy)
{
    memset(dist, -1, sizeof dist);
    queue<Node> q;
    q.push({sx, sy});
    dist[sx][sy]=0;
    while(!q.empty()) {
        Node curr=q.front();
        q.pop();
        int x=curr.x;
        int y=curr.y;
        if(a[x][y]=='D') {
            return dist[x][y];
        }
        for(int i=0; i<8; i++) {
            int nx=x+dx[i];
            int ny=y+dy[i];
            if(nx >= 1 && nx <= N && ny >= 1 && ny <= M) {
                if(a[nx][ny] != '#' && dist[nx][ny]==-1) {
                    dist[nx][ny]=dist[x][y]+1;
                    q.push({nx, ny});
                }
            }
        }
    }
    return -1;
}

int main()
{
    int sx, sy, ex, ey;
    cin>>N>>M;
    for(int i=1; i<=N; i++)
    {
        for(int j=1; j<=M; j++){
            cin>>a[i][j];
            if(a[i][j]=='C'){
                sx=i, sy=j;
            }
            if(a[i][j]=='D'){
                ex=i, ey=j;
            }
        }
    }
    int ans=bfs(sx, sy)/2;
    if(ans>=0)
    {
        cout<<"YES\n"<<ans;
    }
    else cout<<"NO";
    return 0;
}

全部评论

(0) 回帖
加载中...
话题 回帖

本文相关内容

等你来战

查看全部

热门推荐