MnZn刚学OI一秒,SPFA负环模板求助
查看原帖
MnZn刚学OI一秒,SPFA负环模板求助
526895
WYZ20030051楼主2023/7/10 20:22
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<cstdlib>
using namespace std;
#define ll long long
#define ull unsigned long long
int read()
{
	int now=0,nev=1; 
	char c=getchar();
	while(c<'0' || c>'9') 
	{ 
		if(c=='-') 
			nev=-1; 
		c=getchar();
	}
	while(c>='0' && c<='9') 
	{ 
		now=(now<<1)+(now<<3)+(c&15); 
		c=getchar(); 
	}
	return now*nev;
}
const int MAXN=1e5+10;
const int INF=1e9;
int n,m;
int head[MAXN],tt=0;
struct edge
{
	int to,nxt,dis;
}e[MAXN<<1];
void add(int x,int y,int z)
{
	e[++tt].nxt=head[x];
	head[x]=tt;
	e[tt].to=y;
	e[tt].dis=z;
}
queue<int>q;
int dis[MAXN];
bool vis[MAXN];//常规SPFA需要的数组dis,vis 
int cnt[MAXN];//cnt[x]记录节点1~x入队的次数。SPFA判负环的原理是若有某个点 入队次数>=n+1,则该点在负环上
bool SPFA()
{
	memset(dis,INF,sizeof(dis));
	memset(vis,false,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	dis[1]=0,vis[1]=true;//从1开始遍历
	q.push(1);
	while(!q.empty()) 
	{
		int u=q.front();//遍历当前节点 
		q.pop();
		vis[u]=false;
		for(int i=head[u];i;i=e[i].nxt)//遍历相邻节点 
		{
			int v=e[i].to;
			int w=e[i].dis;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				cnt[v]=cnt[u]+1;
				if(cnt[v]>=n)
					return true;//存在负环 
				if(!vis[v])//若与点u相邻的下一节点还未走过 
				{
					q.push(v);//则入队 
					vis[v]=true;//并标记为走过 
				}
			}
			
		}
	}
	return false;
} 
int main()
{
	int t;
	t=read();
	while(t--)
	{
		memset(head,0,sizeof(head));
		tt=0;
		int n,m;
		n=read(),m=read();
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			x=read(),y=read(),z=read();
			if(z<0)
				add(x,y,z);
			else
				add(x,y,z),add(y,x,z);
		}
		if(SPFA())
			printf("YES\n");
		else
			printf("NO\n");
	}
	return 0;
}
2023/7/10 20:22
加载中...