【模板】Johnson

既然\(Floyd\)\(\operatorname{O}(V^3)\),而\(Dijkstra\)\(\operatorname{O}(V\log(E))\),那我们就跑\(V\)\(Dijkstra\)吧!

如果有负环的话就用\(SPFA\)先判一下,为了防止负边权给\(Dijkstra\)造成麻烦,我们就用一个函数\(h(i)\)将一个点对应到整数上。

令:$$\overline\omega(u,v)=\omega(u,v)+h(u)-h(v)$$

\(Dijkstra\)\(dis(u,v)(u,v\in V)\)

则此时最后的$$dis(u,v)=\overline{dis}(u,v)-h(u)+h(v)$$

#include <stdio.h>
#include <queue>
#include <cstring>
using namespace std;
const int z = 1024;
int n, m;

struct EDGE {
	int f, t, next;
	int w;
} edge[z<<2];
int head[z], tot;
int h[z];
void add_edge(int f,int t,int w) {
	edge[++tot].next = head[f];
	edge[tot].f = f;
	edge[tot].t = t;
	edge[tot].w = w;
	head[f] = tot;
}
#define nw(x) (edge[x].w+h[edge[x].f]-h[edge[x].t])

bool vis[z];
int index[z];
bool SPFA(int start) {
	queue<int> q;
	memset(vis,false,sizeof(vis));
	memset(h,0x7f,sizeof(h));
	memset(index,0,sizeof(index));
	q.push(start);
	vis[start] = true;
	h[start] = 0;
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = false;
		for(int i = head[u];i;i = edge[i].next) {
			int v = edge[i].t;
			if(h[v] > h[u]+edge[i].w) {
				h[v] = h[u]+edge[i].w;
				if(!vis[v]) {
					q.push(v);
					vis[v] = true;
					if(++index[v] > n) 
						return false;
				}
			}
		}
	}
	return true;
}

int dis[z][z];
struct NODE {
	int id, data;
	bool operator < (const NODE x) const {
		return x.data < data;
	}
} hp;
void Dijkstra(int start) {
	priority_queue<NODE> q;
	q.push(NODE{start,0});
	memset(dis[start],0x7f,(n+1)*sizeof(int));
	memset(vis,false,(n+1)*sizeof(bool));
	dis[start][start] = 0;
	while(!q.empty()) {
		int u = q.top().id;
		int d = q.top().data;
		q.pop();
		if(!vis[u]) {
			vis[u] = true;
			for(int i = head[u];i;i = edge[i].next) {
				int v = edge[i].t;
				if(dis[start][v] > d+nw(i)) {
					dis[start][v] = d+nw(i);
					q.push(NODE{v,dis[start][v]});
				}
			}
		}
	}
}

bool Johnson() {
	if(SPFA(1)) {
		for(int i = 1;i <= n;++i) 
			add_edge(n+1,i,0);
		SPFA(n+1);
		/*for(int i = 1;i <= n;++i) 
			printf("%d ",h[i]);
		putchar(10);
		for(int i = 1;i <= m;++i) 
			printf("%d -> %d :: %d \n",edge[i].f,edge[i].t,nw(i));
		putchar(10);*/
		for(int i = 1;i <= n;++i) {
			Dijkstra(i);
			/*for(int j = 1;j <= n;++j) 
				printf("%10d ",dis[i][j]);
			putchar(10);*/
			for(int j = 1;j <= n;++j) 
				dis[i][j] = dis[i][j]-h[i]+h[j];
		}
	} else {
		return false;
	}
}

signed main() {
	scanf("%d %d",&n,&m);
	for(int i = 1, a, b, c;i <= m;++i) {
		scanf("%d %d %d",&a,&b,&c);
		add_edge(a,b,c);
	}
	Johnson();
	for(int i = 1;i <= n;++i) {
		printf("%2d :: ",i);
		for(int j = 1;j <= n;++j) 
			printf("%10d ",dis[i][j]);
		putchar(10);
	}
}

@bikuhiku

posted @ 2022-06-24 10:46  bikuhiku  阅读(17)  评论(0编辑  收藏  举报