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;
}