Johnson全源最短路
引入
对于一个无负环的图,我们可以用Floyd或n遍Bellman-ford求出它的全源最短路
Floyd复杂度为O(\(n^3\))在稀疏图上效率极低
n遍Bellman-ford O(\(n^2m\))效率远不及 Floyd
注意到n遍dijstra复杂度为O(\(nm~log~m\))或O(\(n^3\))快于Floyd
但无法在负权图上跑,考虑对边进行重新赋值,使之为非负数
Johnson
注:最终答案\(dis_{i,j}\)为新图上\(dis_{i,j}-h{i}+h_{j}\)
Code
lougu P5905
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,h[3010],cnt;
struct node{
int to,d;
bool operator < (const node &rhs) const{
return d>rhs.d;
}
};
priority_queue<node>q;
struct edge{
int u,v,d,nxt,rd;
}e[9010]; //链式前向星
int hd[3010];
void add(int u,int v,int d){
e[++cnt].d=d;e[cnt].v=v;
e[cnt].nxt=hd[u];e[cnt].u=u;
hd[u]=cnt;
}
bool bellman_ford(){ //计算h[u]
for(int i=1;i<=n;i++) add(0,i,0);
for(int i=1;i<=n;i++) h[i]=1e9;
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt;j++){
int u=e[j].u,v=e[j].v,d=e[j].d;
h[v]=min(h[v],h[u]+d);
}
}
for(int j=1;j<=cnt;j++){
int u=e[j].u,v=e[j].v,d=e[j].d;
if(h[v]>h[u]+d) return 1;
}
for(int i=1;i<=m;i++) e[i].rd=e[i].d+h[e[i].u]-h[e[i].v];
return 0;
}
int vis[3010],dis[3010],f[3010][3010];
void dijstra(int s){
for(int i=1;i<=n;i++) vis[i]=0,dis[i]=1e9;
q.push({s,0});
dis[s]=0;
while(!q.empty()){
int u=q.top().to,d=q.top().d;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=hd[u];i!=0;i=e[i].nxt){
int v=e[i].v,ds=e[i].rd;
if(dis[v]>d+ds){
dis[v]=d+ds;
q.push({v,d+ds});
}
}
}
for(int i=1;i<=n;i++) if(dis[i]!=1e9)f[s][i]=dis[i]-h[s]+h[i];else f[s][i]=1e9;
}
signed main(){
cin>>n>>m;
for(int i=1,x,y,o;i<=m;i++){
cin>>x>>y>>o;
add(x,y,o);
}
if(bellman_ford()){
cout<<"-1";
return 0;
}
for(int i=1;i<=n;i++) dijstra(i);
int sum;
for(int i=1;i<=n;i++){
sum=0;
for(int j=1;j<=n;j++){
sum+=j*f[i][j];
}
cout<<sum<<endl;
}
return 0;
}