传送门
解析:
深入理解 S P F A SPFA SPFA的本质。
思路:
由于是队列优化的 B e l l m a n − F o r d Bellman-Ford Bellman−Ford, S P F A SPFA SPFA也具有判负环的功能,但不同的是 B e l l m a n − F o r d Bellman-Ford Bellman−Ford可以直接求出负环大小。
一般来说,求最短路我们会用 B F S BFS BFS版的 S P F A SPFA SPFA,而判负环我们选择 D F S DFS DFS版的 S P F A SPFA SPFA。
具体实现请看代码。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
int getint(){
re int num;
re char c;
re bool f=0;
while(!isdigit(c=gc()))f^=c=='-';num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return f?-num:num;
}
inline
void outint(ll a){
static char ch[23];
if(a==0)pc('0');
if(a<0)pc('-'),a=-a;
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=1002;
cs int M=100005;
int n,m,s;
int last[N],nxt[M],to[M],ecnt;
ll w[M];
inline
void addedge(int u,int v,ll val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
}
bitset<N> vis,inq,cal;
ll dist[N];
inline
bool SPFA(int u){
cal[u]=inq[u]=true;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(inq[v]||!SPFA(v))return inq[u]=false;
}
}
inq[u]=false;
return true;
}
queue<int> q;
inline
void spfa(int s){
inq.reset();
vis.reset();
memset(dist,0x3f,sizeof dist);
q.push(s);dist[s]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=true;
inq[u]=false;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(!inq[v])q.push(v),inq[v]=1;
}
}
}
}
signed main(){
n=getint();
m=getint();
s=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint(),val=getint();
if(u==v&&val<0){puts("-1");return 0;}
addedge(u,v,val);
}
inq.reset();
vis.reset();
cal.reset();
for(int re i=1;i<=n;++i){
if(!cal[i])
if(!SPFA(i)){puts("-1");return 0;}
}
spfa(s);
for(int re i=1;i<=n;++i){
if(!vis[i])puts("NoPath");
else outint(dist[i]),pc('\n');
}
return 0;
}