本来有负边的最短路应该是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
");
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
", ins[i]);
}
return 0;
}