【图论】Johnson算法(多源最短路优化)

样例题的话随便找个Floyd算法自己测一下吧,下面上封装后的Johnson板子:
(好啦…既然你们懒那我给你们找个吧。。AcWing.854)
链接:https://www.acwing.com/problem/content/description/856/

#include<bits/stdc++.h>
#define ll long long
#define white 0
#define black 1
#define grey  2
#define endl '\n'
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e3+5;
ll n,m,k;ll d[maxn],backup[maxn],h[maxn];
ll dis[maxn][maxn],dd[maxn],color[maxn],target[maxn][maxn];
struct node{
	ll u,v,w;
}edge[25000];
void Bellman_ford(ll s){
	memset(d,INF,sizeof(d));
	d[s]=0;
	for(ll i=1;i<=n+1;i++){
		memcpy(backup,d,sizeof(d));
		for(ll j=1;j<=m+n;j++){
			ll u=edge[j].u,v=edge[j].v,w=edge[j].w;
			if(backup[u]!=INF&&d[v]>backup[u]+w){
				d[v]=backup[u]+w;
			}
		}
	}
}
void dijkstra(ll s){
	for(ll i=1;i<=n;i++){
		dd[i]=INF,color[i]=white;
	}
	dd[s]=0;color[s]=grey;
	while(1){
		ll mind=INF,u=-1;
		for(ll i=1;i<=n;i++){
			if(dd[i]<mind&&color[i]!=black){
				mind=dd[i];
				u=i;
			}
		}
		color[u]=black;
		if(u==-1) break;
		for(ll v=1;v<=n;v++){
			if(dis[u][v]!=INF&&color[v]!=black){
				if(dd[v]>dd[u]+dis[u][v]){
					dd[v]=dd[u]+dis[u][v];
					color[v]=grey;
				}
			}
		}
	}
}
int main(){
	cin>>n>>m>>k;
	for(ll i=1;i<=m;i++){
		ll u,v,w;
		cin>>edge[i].u>>edge[i].v>>edge[i].w;
	}
	for(ll i=m+1;i<=m+n;i++){
		edge[i].u=0;edge[i].v=i-m;edge[i].u=0;
	}
	Bellman_ford(0);
	for(ll i=1;i<=n;i++) {h[i]=d[i];}
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=n;j++){
			dis[i][j]=INF;
			if(i==j) dis[i][j]=0;
		}
	}
	for(ll i=1;i<=m;i++){
		ll u=edge[i].u,v=edge[i].v,w=edge[i].w;
		if(dis[u][v]>w+h[u]-h[v]) dis[u][v]=w+h[u]-h[v];
	}
	for(ll i=1;i<=n;i++){
		dijkstra(i);	
		for(ll j=1;j<=n;j++){
			target[i][j]=dd[j]+h[j]-h[i];
		}
	}
	while(k--){
		ll s,e;cin>>s>>e;
		if(target[s][e]<INF/2) cout<<target[s][e]<<endl;
		else puts("impossible");
	}
}
/*
3 3 2
1 2 1
2 3 2
1 3 1
2 1
1 3
output:
impossible
1
*/

相比较Floyd算法O(n^3)的复杂度,Johnson算法将时间复杂度优化到了O(nnlogn),快了一个量级。
但是呢,代码量是远大于Floyd算法的,而且我搜了很多官方的材料(搭梯子就不多说了没啥用),讲的都很片面,而且呢那些代码也是出了奇的丑陋…根本不适合萌新去阅读和理解。所以我自己亲自写一份吧。


步入正题:

Johnson 和 Floyd 一样,是一种能求出无负环图上任意两点间最短路径的算法。该算法在 1977 年由 Donald B. Johnson 提出。

在这里插入图片描述
emmm,大概意思我解释一下:就是你先新建立一个节点node(4),然后通过Bellman_Ford算法求其到任何一个点的最短路径h[i],为什么要用Ford算法呢,因为Dijskstra算法处理不了负边(原理是Dijkstra算法是基于贪心的思想求最大边),而Ford可以处理负权边。
在这里插入图片描述
这样呢,我就把所有的边转化成正数了。
然后就利用Dijkstra算法去对每一个node点执行最短路操作,求出该点u到v的距离,并记录,最后线性查询就行了。记得更新最短距离的时候,是h[v]-h[u]。
在这里插入图片描述

发布了90 篇原创文章 · 获赞 6 · 访问量 5007

猜你喜欢

转载自blog.csdn.net/Rainfoo/article/details/104496300
今日推荐