首页 > 其他分享 >Johnson全源最短路

Johnson全源最短路

时间:2022-11-16 14:36:43浏览次数:87  
标签:ch Johnson 全源 短路 long ll

Johnson全源最短路:

n个点m条边
Johnson全源最短路算法
主要解决负环问题的全源最短路径算法

主要思路:

1.SPFA判断负环,在跑SPFA之前建立一个[超级源点]标号为0
与每一个点之间都存在一条 长度为0的路径
跑SPFA记录[0]到每个点的最短路 记为 h[i]
用此方法可以标记存在的负环
2.在跑Dijkstra之前调整每条边边权为非负
若u->v边权为w 那么将每条边边权都增加 h[u]-h[v],统计答案时需减去
证明:先画个图,利用三角形三边关系定理可得 w+h[u]>=h[v]
移项可得 w+h[u]-h[v]>=0 所以在w上加 h[u]-h[v]即可保证非负
3.跑n次Dijkstra(堆优化) 复杂度为O(n^2logm)
算法时间复杂度为O(n^2logm)

My_Code:

#include<bits/stdc++.h>
#define int long long
using namespace std;

typedef long long ll;
const ll N=1e4+6010;
const ll inf=1e9;

ll read() {

	ll x=0,f=1;
	char ch=getchar();
	while(ch<48||ch>57) {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>=48&&ch<=57) {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;

}

ll head[N],to[N*2],dis[N*2],nxt[N*2],tot=0;

void add(int u,int v,int w) {

	nxt[++tot]=head[u];
	to[tot]=v;
	dis[tot]=w;
	head[u]=tot;

}

ll n,m;
ll h[N],cnt[N];
ll vis[N];

bool spfa(ll s) {

	queue<ll> p;
	for(ll i=1; i<=n; i++) {

		h[i]=inf;
		vis[i]=false;
		cnt[N]=0;

	}

	p.push(s);
	h[s]=0;
	cnt[s]++;
	vis[s]=true;
	
	while(!p.empty()) {

		ll u=p.front();
		p.pop();
		vis[u]=false;
		for(ll i=head[u]; i; i=nxt[i]) {

			ll v=to[i],w=dis[i];
			if(h[v]>h[u]+w) {

				h[v]=h[u]+w;
				if(vis[v]==false) {

					p.push(v);
					vis[v]=true;
					cnt[v]++;
					if(cnt[v]>=n+1) return true;

				}

			}

		}

	}
	return false;

}

ll d[N];
void Dijkstra(ll s) {

	priority_queue<pair<ll,ll>> q;
	for(ll i=1; i<=n; i++) {

		d[i]=inf;
		vis[i]=0;

	}
	d[s]=0;
	q.push(make_pair(0,s));

	while(!q.empty()) {

		ll u=q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		
		for(ll i=head[u]; i; i=nxt[i]) {

			ll v=to[i],w=dis[i];
			if(d[v]>d[u]+w) {

				d[v]=d[u]+w;
				q.push(make_pair(-d[v],v));

			}

		}

	}

}

signed main() {

	n=read();
	m=read();

	for(int i=1; i<=m; i++) {

		int u=read(),v=read(),w=read();
		add(u,v,w);

	}
	for(int i=1; i<=n; i++) {

		add(0,i,0);//加入超级源点0

	}

	if(spfa(0)) {

		printf("-1\n");
		return 0;

	}

	for(int u=1; u<=n; u++) {

		for(int i=head[u]; i; i=nxt[i]) {

			int v=to[i];
			dis[i]+=(h[u]-h[v]);

		}

	}

	for(int i=1; i<=n; i++) {

		Dijkstra(i);
		int ans=0;
		for(int j=1; j<=n; j++) {

			if(d[j]==inf) ans+=inf*j;
			else ans+=j*(d[j]-(h[i]-h[j]));

		}
		printf("%lld\n",ans);

	}

	return 0;
}

标签:ch,Johnson,全源,短路,long,ll
From: https://www.cnblogs.com/Diamondan/p/16895802.html

相关文章

  • C++ 不知图系列之基于链接表的无向图最短路径搜索
    1.前言图的常用存储方式有2种:邻接炬阵。链接表。邻接炬阵的优点和缺点都很明显。优点是简单、易理解,但是对于大部分图结构而言,都是稀疏的,使用矩阵存储,空间浪费......
  • 道长的算法笔记:基础最短路模型
    #include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>ii;//移动轨迹向量化intadd[3]={+1,-1,0};intmul[3]={0,0,1};intvist[10000......
  • 最短路径树
    最短路径树,即ShortestPathTree,对于一张无向图,固定一个源点,树上每个点到源点的最短距离都等于原图中该点到源点的最短距离。最短路径树是所有路径树中边权和最小的。通......
  • SPFA最短路算法
    ShortestPathFastestAlgorithm(spfa)单源最短路、存在负权边这个算法因为与Bellman-Ford算法比较相似,只是在它的算法的基础上进行了队列优化,因此也被嘲讽为“队列优......
  • Johnson全源最短路
    Johnson通过另一种方法给每条边重新标注边权。新建一个虚拟结点0,向其他所有点连一条边权为0的边,用Bellman-Ford或SPFA算法求出0到其他所有点的最短路记为gpe[i],对于一条x->......
  • AtCoder Beginner Contest 277 E // 最短路
    CrystalSwitches题目来源:AtCoderBeginnerContest277E-CrystalSwitches题目链接:E-CrystalSwitches(atcoder.jp)题意给定一个\(N\)个点\(M\)条边的无向图。......
  • (AtCoder Beginner Contest 277)E(分层图+最短路 or bfs搜两种状态)
    E-CrystalSwitches题目大意:给你n个点,m条边,连接成一个无向图,每个边最初有一个状态(0or1)表示是否能够通过,同时给k个开关位于k的顶点上,每次点击开关会使得所有路的状......
  • #10077. 「一本通 3.2 练习 3」最短路计数
    问1~n的最短路有几个 #include<iostream>#include<cstring>#include<queue>usingnamespacestd;constintN=1e6+2,M=2e6+2;constintinf=0x3f3f3f3f,m......
  • 两个人从不同点出发,然后相遇的最短路问题
    MovingBothHands//可以选择一个中转点//也就是先正着走到这个点//然后再从这个点开始反着走//但是如果已经开始反着走了,那就只可以反着走图//正着和反着跑,有点奇......
  • 最短路径及最低成本算法实现模型
     在vs环境下进行的操作用两种方法分别模拟实现公园导航1.Dijkstra算法按路径长度递增次序来产生最短路径算法;  dist【】距离,path【】前结点  ①初始化......