2024icpc(Ⅱ)网络赛补题E

E. Escape

思路:

可以看成 Sneaker 和杀戮机器人都不能在原地停留,然后杀戮机器人有个活动范围限制。如果 Sneaker 和杀戮机器人可以在原地停留,那么 Sneaker 到达一个点肯定会尽可能早,而且时间必须比杀戮机器人到达这个点短。那么预处理一下每个点最早什么时候会被杀戮机器人到达,然后在这个基础上处理出1 ∼n 的最短路即可。

由于每个机器每个时刻都不会停。我们需要分奇数和偶数时刻,来记录它们会出现的位置。

我们把点拆分为i,i+n两个点做记录。

先预处理bfs,记录所有机器人的可达点。

再跑一遍bfs,计算从起点到终点,需要的最短路径。单组数据时间复杂度 O(n + m)。

代码:

c 复制代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 1e5 + 5;
const int mod = 998244353;
#define ll long long
const int maxn = 1000010;
#define inf 2000000000

int n, m, d;
vector<int> g[maxn];
int k;
int dis[maxn];
int pre[maxn];
int dis2[maxn];
int u, v;
bool vis[maxn];

void solve()
{
    scanf("%lld%lld%lld", &n, &m, &d);
    // init
    for (int i = 0; i <= n; ++i)
    {
        g[i].clear();
        vis[i] = vis[i + n] = 0;
        pre[i] = pre[i + n] = 0;
        dis[i] = dis[i + n] = inf;
        dis2[i] = dis2[i + n] = inf;
    }
    // build gragh
    for (int i = 1; i <= m; ++i)
    {
        scanf("%lld%lld", &u, &v);
        --u, --v; // 点下标偏移到[0,n-1]
        g[u].push_back(v);
        g[v].push_back(u);
    }
    // cal dis2.
    scanf("%lld", &k);
    queue<int> q;
    for (int i = 1; i <= k; ++i)
    {
        scanf("%lld", &u);
        --u; // 点下标偏移到[0,n-1]
        q.push(u);
        vis[u] = 1;
        dis2[u] = 0;
    }
    while (!q.empty())
    {
        u = q.front();
        q.pop();
        int f = u / n; // 偶数/奇数时刻
        int x = u % n; // 原始点
        if (dis2[u] == d)
        { // 超出范围
            continue;
        }
        for (auto v : g[x])
        {
            int y = v + n * (!f); // 下一个点
            if (!vis[y] && dis2[y] > dis2[u] + 1)
            {
                dis2[y] = dis2[u] + 1;
                q.push(y);
                vis[y] = 1;
            }
        }
    }

    // cal dis.
    for (int i = 0; i <= 2 * n; ++i)
    {
        vis[i] = 0;
    }
    pre[0] = -1; // 记录位置,便于输出答案
    dis[0] = 0;
    q.push(0);
    vis[0] = 1;
    while (!q.empty())
    { // bfs过程同上,不赘述
        u = q.front();
        q.pop();
        int f = u / n;
        int x = u % n;

        for (auto v : g[x])
        {
            int y = v + n * (!f);
            if (dis[y] <= dis[u] + 1)
            {
                continue;
            }
            if (dis[u] + 1 >= dis2[y])
            {
                continue;
            }
            dis[y] = dis[u] + 1;
            pre[y] = u;
            q.push(y);
            vis[y] = 1;
        }
    }

    if (!vis[n - 1] && !vis[2 * n - 1])
    { //
        printf("-1\n");
        return;
    }
    int ed = dis[n - 1] < dis[2 * n - 1] ? n - 1 : 2 * n - 1;
    printf("%lld\n", dis[ed]);
    vector<int> res;
    while (ed != -1)
    {
        res.push_back(ed);
        ed = pre[ed];
    }
    reverse(res.begin(), res.end());
    for (auto x : res)
    {
        // 这里 x % n 求出原始点,
        // +1是为了复位,偏移到 [1,n]
        printf("%lld ", x % n + 1);
    }
    printf("\n");
}

signed main()
{
    // std::ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    int t = 1;
    scanf("%lld", &t);
    while (t--)
    {
        solve();
    }

    return 0;
}
相关推荐
月明长歌11 小时前
【码道初阶】一道经典简单题:多数元素(LeetCode 169)|Boyer-Moore 投票算法详解
算法·leetcode·职场和发展
wadesir11 小时前
C语言模块化设计入门指南(从零开始构建清晰可维护的C程序)
c语言·开发语言·算法
t1987512811 小时前
MATLAB水声信道仿真程序
开发语言·算法·matlab
CoderYanger12 小时前
动态规划算法-简单多状态dp问题:15.买卖股票的最佳时机含冷冻期
开发语言·算法·leetcode·动态规划·1024程序员节
Xの哲學12 小时前
Linux RTC深度剖析:从硬件原理到驱动实践
linux·服务器·算法·架构·边缘计算
狐5712 小时前
2025-12-04-牛客刷题笔记-25_12-4-质数统计
笔记·算法
小O的算法实验室12 小时前
2024年IEEE IOTJ SCI2区TOP,基于混合算法的水下物联网多AUV未知环境全覆盖搜索方法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
洲星河ZXH13 小时前
Java,比较器
java·开发语言·算法
CoderYanger13 小时前
递归、搜索与回溯-FloodFill:33.太平洋大西洋水流问题
java·算法·leetcode·1024程序员节
CodeByV13 小时前
【算法题】双指针(二)
数据结构·算法