[CF1472G] Moving to the Capital

[CF1472G] Moving to the Capital - 最短路

Description

有 n 个结点的有向图,边长为 1,已知 di 表示 1 到 i 的最短路长,现在在第 s 个结点上,有两种操作:沿着某条边,走到一个 d 更大的点;沿着某条边,走到一个 d 小于等于当前的点(只能走一次)。求每个点出发,能走到的点中,di 最小的是多少。

Solution

一个显然的性质是,特殊操作一定会留在最后用

由于那种可以使用多次的转移边构成的一定是一个 DAG,所以可以考虑用记忆化搜索来处理最后的问题

我们先求出每个点能直接到达的 d 最小的点的 d,然后以这个为权值,跑一次搜索即可

#include <bits/stdc++.h>
using namespace std;
#define reset(x) memset(x, 0, sizeof x)
#define reset3f(x) memset(x, 0x3f, sizeof x)
namespace sp
{
    const int N = 1e+6 + 5;
    vector<pair<int, int>> g[N];
    int n, v0 = 1, d[N], v[N];
    void make(int t1, int t2, int t3)
    {
        g[t1].push_back(make_pair(t2, t3));
    }
    void reset_graph()
    {
        for (int i = 0; i <= n; i++)
            g[i].clear();
    }
    void solve()
    {
        priority_queue<pair<int, int>> qu;
        for (int i = 0; i <= n + 2; i++)
            d[i] = 1e9;
        for (int i = 0; i <= n + 2; i++)
            v[i] = 0;
        d[v0] = 0;
        qu.push(make_pair(0, v0));
        while (qu.size())
        {
            int p = qu.top().second, r = qu.top().first;
            qu.pop();
            if (r + d[p])
                continue;
            for (int i = 0; i < g[p].size(); i++)
            {
                int q = g[p][i].first, w = g[p][i].second;
                if (d[q] > d[p] + w)
                {
                    d[q] = d[p] + w;
                    qu.push(make_pair(-d[q], q));
                }
            }
        }
    }
} // namespace sp

void solve()
{
    int n, m, u, v;
    cin >> n;
    sp::n = n;
    sp::reset_graph();
    cin >> m;
    vector<vector<int>> g(n + 2);
    for (int i = 1; i <= m; i++)
    {
        cin >> u >> v;
        sp::make(u, v, 1);
        g[u].push_back(v);
    }
    sp::v0 = 1;
    sp::solve();
    auto &d = sp::d;
    vector<int> f(n + 2);
    for (int i = 1; i <= n; i++)
        f[i] = d[i];
    for (int i = 1; i <= n; i++)
        for (int j : g[i])
            f[i] = min(f[i], d[j]);
    vector<int> vis(n + 2);

    function<int(int)> dfs = [&](int p) -> int {
        if (vis[p])
            return f[p];
        vis[p] = 1;
        for (int q : g[p])
            if (d[q] > d[p])
                f[p] = min(f[p], dfs(q));
        return f[p];
    };

    for (int i = 1; i <= n; i++)
        if (!vis[i])
            dfs(i);
    for (int i = 1; i <= n; i++)
        cout << f[i] << " ";
    cout << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--)
        solve();
}
原文地址:https://www.cnblogs.com/mollnn/p/14365361.html