SPFA判断负环
https://blog.csdn.net/forever_dreams/article/details/81161527
【bfs版】
首先我们要知道,对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有 n 个
这样的话,我们用 cnt[ i ] 表示从起点(假设就是 1)到 i 的最短距离包含点的个数,初始化 cnt[ 1 ] = 1,
那么当我们能够用点 u 松弛点 v 时,松弛时同时更新 cnt[ v ] = cnt[ u ] + 1,若发现此时 cnt[ v ] > n,那么就存在负环
还有一种方法是记录每个点的入队次数,入队次数大于 n 就说明有负环,但是这样做一般都要比上面的方法慢。举个例子,在一个由 n 个点构成的负环中,这个方法要绕环 n 次,
而上面的方法绕环 1 次就行了
代码(Yes 是存在负环,No 是不存在负环,图是联通的)

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=10100;
const int maxm=20050;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
/*
SPFA判断负环 
https://blog.csdn.net/forever_dreams/article/details/81161527
【bfs版】
首先我们要知道,对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有 n 个
这样的话,我们用 cnt[ i ] 表示从起点(假设就是 1)到 i 的最短距离包含点的个数,初始化 cnt[ 1 ] = 1,
那么当我们能够用点 u 松弛点 v 时,松弛时同时更新 cnt[ v ] = cnt[ u ] + 1,若发现此时 cnt[ v ] > n,那么就存在负环
还有一种方法是记录每个点的入队次数,入队次数大于 n 就说明有负环,但是这样做一般都要比上面的方法慢。举个例子,在一个由 n 个点构成的负环中,这个方法要绕环 n 次,
而上面的方法绕环 1 次就行了
代码(Yes 是存在负环,No 是不存在负环,图是联通的)
*/ 
int head[maxn],to[maxm],nex[maxm],wei[maxm];
int num,n,m;
int vis[maxn],dis[maxn],cnt[maxn];
bool flag;
void adde(int x,int y,int z){
	to[++num]=y;
	nex[num]=head[x];
	wei[num]=z;
	head[x]=num;
}
bool spfa(int s){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	queue<int> q;
	q.push(s);
	vis[s]=1;
	cnt[s]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(int i=head[x];i;i=nex[i]){
			int t=to[i];
			if(dis[t]>dis[x]+wei[i]){
				dis[t]=dis[x]+wei[i];
				cnt[t]=cnt[x]+1;
				if(cnt[t]>n) return false;
				if(!vis[t]) {
					q.push(t);
					vis[t]=1;
				} 
			}
		}
	}
	return true;
}
int main(){
	scanf("%d %d",&n,&m);
	int x,y,z;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x,&y,&z);
		adde(x,y,z);
	}
	flag=spfa(1);
	if(flag) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	
return 0;
}

  

【dfs版】
基于 dfs 版的 SPFA 相当于是把"先进先出"的队列换成了"先进后出"的栈
也就是说,每次都以刚刚松弛过的点来松弛其他的点,如果能够松弛点 x 并且 x 还在栈中,那图中就有负环
一般来说的话,若存在负环,那么 dfs 会比 bfs 快
但是如果不存在负环,dfs 可能会严重影响求最短路的效率,要谨慎使用

void spfa(int x){
	vis[x]=1;
	for(int i=head[x];i;i=nex[i]){
		int t=to[i];
		if(dis[t]>dis[x]+wei[i]){
			if(vis[t]) {
				flag=false;
				return;
			}
			dis[t]=dis[x]+wei[i];
			spfa(t);
		}
	}
	vis[x]=false; //要回溯 
}

int main(){
	memset(dis,0x3f,sizeof(dis));
	d[1]=0;
	spfa(1);
} 

  

 

 posted on 2020-08-08 16:59  shirlybabyyy  阅读(185)  评论(0编辑  收藏  举报