Johnson 全源最短路
本来有负边的最短路应该是O(n^3)
这个算法把负权图改成了正权图,可以跑dij,能够用来优化多次涉及spfa的算法,比如费用流
十分神奇
核心想法:
1.建立0--->(1--n),然后跑个spfa,得到d[i--n],
2.把x--->y----len改成 x--->y-----len - d[y] + d[x]
最后的结果就是a----b = dis[b] - d[b] + d[a];
完了
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; typedef long long ll; ll INF = 1e17; const int maxn = 2e5 + 111; struct Node { int p; ll len; Node(int a, ll b) :p(a), len(b) {} }; vector<Node>G[maxn]; void add(int be, int en,int len) { G[be].push_back(Node(en, len)); } int n, m; ll dis[maxn]; int cnt[maxn]; int h[maxn]; int vis[maxn]; int spfa(int s) { queue<int>que; for (int i = 0; i <= n ; i++) { vis[i] = cnt[i] = 0; dis[i] = INF; } que.push(s); dis[s] = 0; while (que.size()) { int x = que.front(); que.pop(); vis[x] = 0; for (int i = 0; i < G[x].size(); i++) { int p = G[x][i].p; ll ln = G[x][i].len; if (dis[p] > dis[x] + ln) { dis[p] = dis[x] + ln; if (vis[p] == 0) { vis[p] = 1; que.push(p); if (++cnt[p] > n) return 1; } } } } return 0; } bool operator <(const Node a, const Node b) { return a.len > b.len; } int dij(int s) { for (int i = 0; i <= n; i++) { vis[i] = 0; dis[i] = INF; } priority_queue<Node>que; que.push(Node(s, 0)); dis[s] = 0; while (que.size()) { Node ans = que.top(); que.pop(); if (vis[ans.p]) continue; vis[ans.p] = 1; for (int i = 0; i < G[ans.p].size(); i++) { int p = G[ans.p][i].p; ll ln = G[ans.p][i].len; if (dis[p] > dis[ans.p] + ln) { dis[p] = dis[ans.p] + ln; que.push(Node(p, dis[p])); } } } return 0; } vector<ll> ins; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { add(0, i, 0); } for (int i = 0; i < m; i++) { int be, en, len; scanf("%d %d %d", &be, &en, &len); add(be, en, len); } int f = spfa(0); if (f) { printf("-1\n"); return 0; } for (int i = 0; i <= n; i++) h[i] = dis[i]; for (int i = 1; i <= n; i++) { for (int j = 0; j < G[i].size(); j++) { G[i][j].len += dis[i] - dis[G[i][j].p]; } } for (int i = 1; i <= n; i++) { dij(i); ll ans = 0; for (int j = 1; j <= n; j++) { if (dis[j] == INF) dis[j] = 1e9; else dis[j] -= h[i] - h[j]; ans += 1LL*j*dis[j]; } ins.push_back(ans); } for (int i = 0; i < ins.size(); i++) { printf("%lld\n", ins[i]); } return 0; }
寻找真正的热爱