SPFA

虽然SPFA已死,但是SPFA还是很有用处的

具体实现与dijkstra 相似,但是是利用队列优化,在广度上进行求解(可处理负边权),在每次松弛时,保证所有深度为n的路径最短

应用

1.存在负边权
2.每个点可以被多次经过
3.判断负(正)环

code

#include<iostream>
#include<cstdio>
#include<math.h>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define ll long long

const ll maxn=3e3+10;
ll t,n,m,tot;
ll dis[maxn],vis[maxn],ru[maxn],head[maxn];
std::vector<std::pair<ll,ll> > e[maxn]; 

inline void cl()
{
	tot=0;
	memset(head,0,sizeof(head));
	for(int i=1;i<=n;i++) e[i].clear();
}

inline bool spfa(ll x)
{
	for(int i=1;i<=maxn;i++) dis[i]=0x7fffffff,vis[i]=0,ru[i]=0;
	std::queue<ll> q;
	
	dis[x]=0;
	vis[x]=1;
	
	q.push(x);
	
	while(q.size())
	{
		ll u=q.front();
		q.pop();
		
		vis[u]=0;
		
		for(int i=0;i<e[u].size();i++)
		{
			ll v=e[u][i].first;
			ll w=e[u][i].second;
			
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				
				if(!vis[v])
				{
					q.push(v);
					vis[v]=1;
					
					ru[v]++;
					
					if(ru[v]>=n)//当存在负环时,会不断经过环上的路径更新最小值,当一条路径被走过了 n 次以上,那么图中必然存在负环
					{
						return 1;
					}
				}
			}
		}
	}
	
	return 0;
}

int main(void)
{
	scanf("%lld",&t);
	
	while(t--)
	{
		cl();
		
		scanf("%lld %lld",&n,&m);
		
		for(int i=1;i<=m;i++)
		{
			ll x,y,z;
			scanf("%lld %lld %lld",&x,&y,&z);
			
			if(z>=0) e[y].push_back(std::make_pair(x,z));
			e[x].push_back(std::make_pair(y,z));
		}
		ll flag=spfa(1);
		
		if(flag) printf("YES\n");
		else printf("NO\n"); 
	}
	return 0;
}
posted @ 2020-12-01 11:06  雾隐  阅读(300)  评论(0编辑  收藏  举报