题目链接
https://www.acwing.com/problem/content/description/854/
SPFA判负环的标准模板。
思路:
在SPFA的过程中统计每个点的“最短路径的长度”,若一个点的最短路径的长度>=n(n是总点数),那么就说明一定存在“负环”了,这个事情不难证明。
这里有一个技巧,就是引入了一个虚拟源点0号点,让这个0号点和所有点都连边,然后从0号点开始运行spfa算法。
这么做的原因实际上在于,就是spfa算法实际上还是一个“单源最短路”,i.e. 计算其余所有点到某一个点的最短路,那么如果负环和某一个点x并不连通,那么从该点x开始运行spfa算法就没有办法检测到这个负环了。引入了这个虚拟源点,就能保证一定和负环相连
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
int dis[N];
int num[N]; // the number of shortest route of each point
int st[N];
int n,m;
struct node{
int v;
int w;
};
vector<node> e[N];
int q[N];
int tt,hh;
int ans=0;
void spfa(){
memset(dis,0x3f,sizeof(dis));
memset(num,0,sizeof(num));
tt=hh=0;
dis[0]=0;
q[tt++]=0;
tt%=N;
st[0]=0;
num[0]=0;
while(tt!=hh){
int cur=q[hh++];
hh%=N;
st[cur]=0;
for(int i=0;i<e[cur].size();i++){
int v=e[cur][i].v;
int w=e[cur][i].w;
if(dis[v]>dis[cur]+w){
dis[v]=dis[cur]+w;
num[v]=num[cur]+1;
if(!st[v]){
st[v]=1;
q[tt++]=v;
tt%=N;
}
}
else if(dis[v]==dis[cur]+w){
if(num[cur]+1<num[v]){
num[v]=num[cur]+1;
if(!st[v]){
st[v]=1;
q[tt++]=v;
tt%=N;
}
}
}
if(num[v]>=(n+1)){
ans=1;
return ;
}
}
}
}
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[a].push_back(node{b,c});
}
for(int i=1;i<=n;i++){
e[0].push_back(node{i,0});
}
spfa();
if(ans) printf("Yes");
else printf("No");
return 0;
}