1 2 3 4

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;
}

  

posted @ 2020-12-04 15:51  Lesning  阅读(72)  评论(0编辑  收藏  举报