@ysner
2020-09-23T12:56:27.000000Z
字数 2222
阅读 1840
负环 最短路
首先来区分一下和
开局不标。
用某点更新的条件是。
中的表示点是否在队列中。
//SPFAqueue<int>Q;memset(d,63,sizeof(d));d[0]=0;vis[0]=1;Q.push(0);while(!Q.empty()){int u=Q.front();Q.pop();for(int i=h[u];i;i=e[i].nxt){int v=e[i].to;if(d[v]>d[u]+e[i].w){a[v]=a[u]+1;if(a[v]>n) return 1;//a代表最短路径所含点数,显然不能超过nd[v]=d[u]+e[i].w;if(!vis[v]) vis[v]=1,Q.push(v);}}vis[u]=0;//}
//Dijkstrapriority_queue<node>Q;for(int i=1;i<=n;i++) dis[i]=1e9,vis[i]=0;Q.push((node){s,0});dis[s]=0;while(!Q.empty()){int u=Q.top().u;Q.pop();if(vis[u]) continue;vis[u]=1;//for(int i=h[u];i;i=e[i].nxt){int v=e[i].to;if(dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;if(!vis[v]) Q.push((node){v,dis[v]});}}}
然后不能用于负权图,故只能把图修成正权的。
怎么办?利用,我们可以把边权改成,而这个一定正。
走任意一条路后,可以发现真实距离就是(为终点,为起点)。因为中途点的一正一负抵消掉了。
#include<bits/stdc++.h>#define ll long longusing namespace std;const int N=3e3+3;struct Edge{int to,nxt,w;}e[N<<2];struct node{int u,dis;bool operator < (const node &o) const{return dis>o.dis;}};int n,m,h[N],a[N],cnt;ll dis[N],d[N],sum;bool vis[N];int gi(){int x=0,t=1;char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}void add(int u,int v,int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}bool SPFA(){queue<int>Q;memset(d,63,sizeof(d));d[0]=0;vis[0]=1;Q.push(0);while(!Q.empty()){int u=Q.front();Q.pop();for(int i=h[u];i;i=e[i].nxt){int v=e[i].to;if(d[v]>d[u]+e[i].w){a[v]=a[u]+1;if(a[v]>n) return 1;d[v]=d[u]+e[i].w;if(!vis[v]) vis[v]=1,Q.push(v);}}vis[u]=0;}return 0;}void Dijstra(int s){priority_queue<node>Q;for(int i=1;i<=n;i++) dis[i]=1e9,vis[i]=0;Q.push((node){s,0});dis[s]=0;while(!Q.empty()){int u=Q.top().u;Q.pop();if(vis[u]) continue;vis[u]=1;for(int i=h[u];i;i=e[i].nxt){int v=e[i].to;if(dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;if(!vis[v]) Q.push((node){v,dis[v]});}}}for(int i=1;i<=n;i++)if(dis[i]==1e9) sum+=i*dis[i];else sum+=i*(dis[i]+d[i]-d[s]);printf("%lld\n",sum);sum=0;}int main(){n=gi();m=gi();while(m--){int u=gi(),v=gi(),w=gi();add(u,v,w);}for(int i=1;i<=n;i++) add(0,i,0);if(SPFA()) {puts("-1");return 0;}for(int u=1;u<=n;u++)for(int i=h[u];i;i=e[i].nxt)e[i].w+=(d[u]-d[e[i].to]);for(int i=1;i<=n;i++)Dijstra(i);return 0;}
