学这个是为了支持在带负权值的图上跑 Dijkstra.

为了这个我们要考虑把负的权值搞正。

那么先把我们先人已经得到的结论摆出来。我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体就是在原图的基础上建立超级源点。

然后我们把得到的这个东西称为 势能 $h$ ,我们对于原图的每条边 $(u,v)$的边权加上 $h_u-h_v$,然后就可以跑 Dijkstra 了,求出的答案是 $dis_{i,j}-h_i+h_j$.然后我们证明这样搞是对的。

首先需要证明这个搞法不会使求出来的值变化。

对于一条 $i$ 到 $j$ 的最短路径,有经过的点集 $S$ ,那么我们求出的最短路是:

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)\]

然后我们不难发现前后两项有部分可以抵消,所以有(设 $d_{i,j}$ 为直接 Dijkstra 跑出的答案):

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)\] \[=d_{i,j}+h_1+h_n\]

在加上势能满足三角形不等式:$w(u,v)+h_u \geqslant h_v$

就是差分约束(和最短路)那个东西啦。然后变形得到所有修改后边权大于0.

就没啦(^-^)

Johnson 全源最短路

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
	while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
	return s*f;
}
const ll INF=1e18;
const int N=3e3+3;
const int M=6e3+3;
int n,m;
struct Edge{
	int v;ll w;
};
vector<int>head,nxt;
vector<Edge>to;
inline void join(int u,int v,int w){
	nxt.push_back(head[u]);
	head[u]=to.size();
	to.push_back({v,w});
}
queue<int>q;
ll h[N];bool inq[N];
int hoop[N];
inline bool SPFA(int s){
	while(!q.empty() ) q.pop();
	for(int i=1;i<=n+1;++i){
		h[i]=INF;inq[i]=0;hoop[i]=0;
	}
	inq[s]=1;q.push(s);h[s]=0;hoop[s]=1;
	while(!q.empty() ){
		int u=q.front();q.pop();inq[u]=0;
		for(int i=head[u];~i;i=nxt[i]){
			int v=to[i].v;ll w=to[i].w;
			if(h[v]>h[u]+w){
				h[v]=h[u]+w;
				if(!inq[v]){
					++hoop[v];
					if(hoop[v]>n) return false;
					q.push(v);
					inq[v]=1;
				}
			}
		}
	}
	return true;
}
ll dis[N][N];int S;
struct node{
	int x;
	inline friend bool operator <(node x,node y){
		return dis[S][x.x]>dis[S][y.x];
	}
};
namespace Dijkstra{
	priority_queue<node>q;
	inline void work(int s){
		while(!q.empty() ) q.pop();
		for(int i=1;i<=n;++i){
			dis[s][i]=INF;
			inq[i]=0;
		}S=s;
		inq[s]=1;q.push({s});dis[s][s]=0;
		while(!q.empty() ){
			int u=q.top().x;q.pop();inq[u]=0;
			for(int i=head[u];~i;i=nxt[i]){
				int v=to[i].v;ll w=to[i].w;
				if(dis[s][v]>dis[s][u]+w){
					dis[s][v]=dis[s][u]+w;
					if(!inq[v]){
						inq[v]=1;
						q.push({v});
					}
				}
			}
		}
	}
}
struct EDGE{
	int u,v,w;
}e[M];
int main(){
	//file(a);
	n=read();m=read();
	head.resize(n+1,-1);
	for(int i=1;i<=m;++i){
		int u=read(),v=read(),w=read();
		join(u,v,w);
		e[i]={u,v,w};
	}
	for(int i=1;i<=n;++i){
		join(0,i,0);
	}
	if(!SPFA(0)) {printf("-1\n");return 0;}
	head.clear();
	head.resize(n+1,-1);
	to.clear();nxt.clear();
	for(int i=1;i<=m;++i){
		join(e[i].u,e[i].v,e[i].w+h[e[i].u]-h[e[i].v]);
	}
	for(int i=1;i<=n;++i){
		Dijkstra::work(i);
	}
	for(int i=1;i<=n;++i){
		ll ans=0;
		for(int j=1;j<=n;++j){
			if(dis[i][j]==INF) ans+=1ll*(1e9)*j;
			else ans+=1ll*(dis[i][j]-h[i]+h[j])*j;
		}
		printf("%lld\n",ans);
	}
	return 0;
}