Codeforces2014E Rendez-vous de Marian et Robin(分层图最短路)

题意

T 组测试数据。
有一个旅行网络,由 n 个点和 m 条边组成。第 i 条边连接顶点 uivi,从一端走到另一端需要花费时间 wi 秒 (保证 wi偶数)。玛丽安和罗宾需要选择在某个点相遇。玛丽安从顶点 1 开始,罗宾从顶点 n 开始。
此外,n 个顶点中的 h 个顶点各有一匹马可用,玛丽安和罗宾都是优秀的骑手,可以在 0 秒内骑上马。骑马时,行进时间减半 (速度加倍)。一旦骑上某一匹马,就可以一直骑着它走完剩余的所有路程。相遇必须在顶点进行。任何一方都可以选择在任何顶点上等待对方。如果罗宾和玛丽安可以相遇,输出最早可以相遇的时间;否则,输出 -1

数据范围:2n2×105, 1m2×1052wi106, wi0(mod  2)
特别地,题目保证 Σn2×105, Σm2×105

题解

不难想到,可以枚举二者相遇的点 u,假设双方以最佳路线到达点 u 需要花费的时间为 T1T2,那么答案就是所有的 max(T1,T2) 的最小值。

考虑以下三种情况:
Case 1:双方都不骑马。
Case 2:一方中途上马。
Case 3:双方都是中途上马。

对于 Case 3,如果双方到达 u 点的最佳路线中,都需要骑上位于位置 i 的马,那么这种情形是不合理的。但是双方在位置 i 相遇一定比在位置 u 相遇更优,因为答案是求所有情况的最小值,所以,答案的正确性可以保证。

我们可以建一个如下的分层图,然后从起点和终点分别跑 Dijkstra 即可。
image

时间复杂度为:O(n log n)

点击查看代码
#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

constexpr i64 inf = 1e18;

void solve() {
    int n, m, h;
    cin >> n >> m >> h;

    vector<vector<pair<int, int>>> adj(2 * n);
    for (int i = 0; i < h; i++) {
        int a;
        cin >> a;
        a--;
        
        adj[a].emplace_back(a + n, 0);
    }
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--; v--;

        adj[u].emplace_back(v, w);
        adj[v].emplace_back(u, w);
        adj[u + n].emplace_back(v + n, w / 2);
        adj[v + n].emplace_back(u + n, w / 2);
    }

    auto dijkstra = [&](int s) {
        priority_queue<pair<i64, int>, vector<pair<i64, int>>, greater<pair<i64, int>>> Q;
        vector<i64> dist(2 * n, inf);
        vector<bool> vis(2 * n, false);

        dist[s] = 0LL;
        Q.emplace(0LL, s);
        while (!Q.empty()) {
            int u = Q.top().second;
            Q.pop();

            if (vis[u]) {
                continue;
            }
            vis[u] = true;
            for (auto [v, w] : adj[u]) {
                if (dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    Q.emplace(dist[v], v);
                }
            }
        }
        
        vector<i64> ans(n);
        for (int i = 0; i < n; i++) {
            ans[i] = min(dist[i], dist[i + n]);
        }
        return ans;
    };

    vector<i64> D1 = dijkstra(0), D2 = dijkstra(n - 1);
    i64 ans = inf;
    for (int i = 0; i < n; i++) {
        ans = min(ans, max(D1[i], D2[i]));
    }

    if (ans == inf) {
		// 无法相遇
        ans = -1;
    }
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    while (T--) {
        solve();
    }
    return 0;
}
posted @   yanhy-orz  阅读(25)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示