• [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();
    }
    
  • 相关阅读:
    Redis 面试题
    Mysql 面试题(一网打尽,收藏版)
    Zookeeper 面试题(一网打净,持续更新)
    SpringBoot 基础知识 核心知识 【收藏版】
    i.MX6 GStreamer-imx Plugins – Tutorial & Example Pipelines
    Getting Started GNSS Application Develop
    protobuf/protobuf-c tutorials
    libpcap packet capture tutorial
    Linux下的实时流媒体编程( IBM Developer)
    Epoll Tutorial
  • 原文地址:https://www.cnblogs.com/mollnn/p/14365361.html
Copyright © 2020-2023  润新知