Bellman-Ford、SPFA 判断负环

Bellman-Ford 负环

Bellman-Ford 会对边进行松弛操作,若不存在负环,则至多松弛 \(n-1\) 轮即可求出最短路,进而确定无负环。

  • 注意需要特判 inf,因为负权。

  • 注意需要 dis[s]=0

vector 实现代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=2e3,inf=0x3f3f3f3f;
int n;
vector<pair<int,int>>g[N+1];
bool BellmanFord(){
	static int dis[N+1];
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	for(int i=1;i<=n;i++){
		bool flag=true;
		for(int x=1;x<=n;x++){
			if(dis[x]==inf){
				continue;
			}
			for(auto [v,w]:g[x]){
				if(dis[x]+w<dis[v]){
					dis[v]=dis[x]+w;
					flag=false;
				}
			}
		}
		if(flag){
			return false;
		}
	}
	return true;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int T;
	cin>>T;
	while(T--){
		int m;
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			g[i].resize(0);
		}
		while(m--){
			int u,v,w;
			cin>>u>>v>>w;
			g[u].push_back({v,w});
			if(w>=0){
				g[v].push_back({u,w});
			}
		}
		if(BellmanFord()){
			cout<<"YES\n";
		}else{
			cout<<"NO\n";
		}
	}
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

边集数组实现代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int N=2e3,M=3e3;
typedef long long ll;
int T,n,m,u,v,w,top;
struct edge{
	int u,v;
	ll w;
}a[2*M+1];
bool Bellman_Ford(int s){
	static ll dis[N+1];
	static bool flag;
	for(int i=1;i<=n;i++)dis[i]=2147483647;
	dis[s]=0;
	for(int i=1;i<=n;i++){
		flag=true;
		for(int j=1;j<=top;j++){
			if(dis[a[j].u]==2147483647)continue;
			if(dis[a[j].u]+a[j].w<dis[a[j].v]){
				dis[a[j].v]=dis[a[j].u]+a[j].w;
				flag=false;
			}
		}
		if(flag)break;
		if(i==n)return true;
	}return false;
}
void Start(){
	top=0;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	scanf("%d",&T);
	while(T--){
		Start();
		scanf("%d %d",&n,&m);
		for(int i=1;i<=m;i++){
			scanf("%d %d %d",&u,&v,&w);
			a[++top]={u,v,w};
			if(w>=0)a[++top]={v,u,w};
		}
		printf("%s\n",(Bellman_Ford(1)?"YES":"NO"));
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

SPFA 负环

记录最短路径长度,若大于等于 \(n\),则存在负环。

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
const ll N=2e3,M=3e3,MAX=1ll<<63-1;
int T,n,m,u,v,w,top,h[N+1];
struct edge{
	int v,r;
	ll w;
}a[2*M+1];
void create(int u,int v,ll w){
	a[++top]={v,h[u],w};
	h[u]=top;
}
bool SPFA(int s){
	static int pl,c[N+1];
	static ll dis[N+1];
	static bool flag[N+1];
	fill(dis+1,dis+n+1,MAX);
	dis[s]=0;
	fill(c+1,c+n+1,0);
	fill(flag+1,flag+n+1,false);
	queue<int>q;
	q.push(s);
	flag[s]=true;
	while(q.size()){
		pl=q.front();
		q.pop();
		flag[pl]=false;
		for(int i=h[pl];i>0;i=a[i].r){
			if(dis[pl]+a[i].w<dis[a[i].v]){
				dis[a[i].v]=dis[pl]+a[i].w;
				c[a[i].v]=c[pl]+1;
				if(c[pl]>=n)return true;
				if(flag[a[i].v]==false)q.push(a[i].v);
			}
		} 
	}return false;
}
void Start(){
	top=0;
	memset(h,0,sizeof(h));
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	scanf("%d",&T);
	while(T--){
		Start();
		scanf("%d %d",&n,&m);
		for(int i=1;i<=m;i++){
			scanf("%d %d %d",&u,&v,&w);
			create(u,v,w);
			if(w>=0)create(v,u,w);
		}
		printf("%s\n",(SPFA(1)?"YES":"NO"));
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

时间复杂度均为 \(\mathcal O(nm)\)


笑话

posted @ 2025-11-25 14:44  TH911  阅读(7)  评论(0)    收藏  举报