AtCoder Beginner Contest 237 E - Skiing(dijkstra处理负权)

E - Skiing

题目大意:

\(n\) 个点每个点有一个点权,依据点权的大小关系确定 \(m\) 条边权,求最长路。

思路:

关于SPFA,他死了。

很明显是求带负权的最长路,赛后有数据毙掉SPFA,考虑如何转化边权使得可以用 dijkstra 求解。

我们将点权看作势能,加入到最短路的求解中。

设原边权为 \(w(u, v)\),新边权为 \(\bar{w}(u, v)=w(u, v)+h[u]-h[v]\)

假设最短路径为 1-->2-->3-->4,

那么新的最短路径为

\[\begin{array}{l} \bar{w}(1,2)+\bar{w}(2,3)+\bar{w}(3,4) \\ =w(1,2)+h[1]-h[2]+w(2,3)+h[2]-h[3]+w(3,4)+h[3]-h[4] \\ =w(1,2)+w(2,3)+w(3,4)+h[1]-h[4] \end{array} \]

可以看到,新的最短路径只与起点和终点的势能有关。

考虑这样转化后的边权。

记取反后的边权为 \(\tilde{w}(u, v)\)

如果 \(h[u] > h[v]\)

\(w(u, y) = h[u] - h[v]\)

\(\tilde{w}(u, y) = h[v] - h[u]\)

\(\bar{w}(u, v) = h[v] - h[u] + h[u] - h[v] = 0\)

如果 \(h[u] < h[v]\)

\(w(u, y) = -2(h[v] - h[u])\)

\(\tilde{w}(u, y) = 2(h[v] - h[u])\)

\(\bar{w}(u, v) = 2(h[v] - h[u]) + h[u] - h[v] = h[v] - h[u] > 0\)

这样,边权加入了势能后就都是非负的,可以运用 dijstra 求最长路。

具体的,得到的答案 \(dis[u]\) 减去势能 \(h[1] - h[u]\),再取反得到最长路,即 \(-(dis[u] - (h[1] - h[u]))\)

Code:
int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<int> h(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> h[i];
    }
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        if (h[u] > h[v]) {
            addedge(u, v, 0);
            addedge(v, u, h[u] - h[v]);
        } else if (h[u] == h[v]) {
            addedge(u, v, 0);
            addedge(v, u, 0);
        } else {
            addedge(v, u, 0);
            addedge(u, v, h[v] - h[u]);
        }
    }

    dijkstra(n, 1);

    ll ans = 0;
    for (int u = 1; u <= n; u++) {
        if (dis[u] == INF)
            continue;
        ans = max(ans, -(dis[u] - (h[1] - h[u])));
    }
    cout << ans << "\n";
    return 0;
}
posted @ 2022-03-03 11:44  Nepenthe8  阅读(98)  评论(0编辑  收藏  举报