• 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
    ");
    		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;
    }
    

      

  • 相关阅读:
    android_自定义布局
    二叉树_学习笔记
    栈的应用-四则表达式(C#代码实现)
    Android Fragment 生命周期
    Android Fragment之间传值
    Android ArrayAdpater 填充集合
    任务和返回栈
    XML Drawable与9-Patches
    《python语言程序设计》_第一章编程题
    CSS-文本超出部分省略号
  • 原文地址:https://www.cnblogs.com/lesning/p/14086253.html
Copyright © 2020-2023  润新知