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;
}
     寻找真正的热爱

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号