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

E - Skiing

题目大意:

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

思路:

关于SPFA,他死了。

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

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

设原边权为 w(u,v),新边权为 w¯(u,v)=w(u,v)+h[u]h[v]

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

那么新的最短路径为

w¯(1,2)+w¯(2,3)+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]

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

考虑这样转化后的边权。

记取反后的边权为 w~(u,v)

如果 h[u]>h[v]

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

w~(u,y)=h[v]h[u]

w¯(u,v)=h[v]h[u]+h[u]h[v]=0

如果 h[u]<h[v]

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

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

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:
Copy
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 @   Nepenthe8  阅读(121)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示