题目大意:
中文题。
解题思路:
带负权的最短路,记录一下每个点入队次数,入队两次即说明存在负环。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<queue> #include<vector> #define LL long long #define db double #define maxnn 10000000 #define EPS 1e-15 #define inf 1000000000 #define pa pair<int,int> using namespace std; const int maxn=101000; int n,m,k,t,x,y,s,z,tot=0; struct edge{ int to,w,next; }e[1010000]; int head[maxn],dist[maxn],ans[maxn]; bool vis[maxn]; int f[maxn]; bool flag; void add(int x,int y,int z){ e[tot].to=y; e[tot].w=z; e[tot].next=head[x]; head[x]=tot++; } bool spfa(int s){ queue<int>q; memset(dist,63,sizeof(dist)); memset(vis,false,sizeof(vis)); memset(ans,0,sizeof(ans)); q.push(s); dist[s]=0; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for (int i=head[u];i!=-1;i=e[i].next){ if (dist[e[i].to]>dist[u]+e[i].w){ dist[e[i].to]=dist[u]+e[i].w; if (!vis[e[i].to]){ vis[e[i].to]=1; int v=e[i].to; q.push(v); if (ans[v]<2) {ans[v]++;} else return true; } } } } return false; } int main(){ scanf("%d%d%d",&n,&m,&s); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); if(x==y && z<0){ printf("-1\n"); return 0; } } for(int i=1;i<=n;i++){ if(spfa(i)){ printf("-1\n"); return 0; } } spfa(s); for(int i=1;i<=n;i++){ if(dist[i]>1000000){ if(i!=s) printf("NoPath\n"); else printf("0\n"); } else printf("%d\n",dist[i]); } return 0; }