申明
再次申明这个专栏只是分享博主学习图论时的顺序,给新手提供一个入门的好方法(博主现在也是新手所以博主写的代码适合C转C++的新手学习),具体算法逻辑需要自己学习,代码区域有部分解释,因此有错误可以私信或者直接在评论区骂。
前言
Spfa算法是Bellman_ford算法的优化,时间复杂度为Onm,实际上低于这个数,Spfa需要邻接表存,有些题会卡Spfa算法。。。
题目链接
P3385 【模板】负环 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
注意这是从1可到达的负环
代码
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
#define ll long long
const int N=2e5+10;
int h[N],e[N],ne[N],w[N],idx;
int dist[N],cnt[N]; //边数
int t,n,m;
bool st[N];
void add(int a,int b,int wa)
{
e[idx]=b,ne[idx]=h[a],w[idx]=wa,h[a]=idx++;
}
bool Spfa()
{
memset(cnt,0,sizeof cnt);
memset(st,false,sizeof st);
memset(dist,0x3f,sizeof dist);
queue<int> q;
dist[1] = 0;
cnt[1] = 1;
q.push(1);
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>n) return true;
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
return false;
}
void solve()
{
idx=0;
memset(h,-1,sizeof h);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
if(w>=0) add(u,v,w),add(v,u,w);
else add(u,v,w);
}
if(Spfa()) printf("YES\n");
else printf("NO\n");
}
int main()
{
scanf("%d",&t);
while(t--) solve();
return 0;
}
扩展
如果是全局是否有负环,那么需要把全部点入队。
代码
数据
1
4 3
2 3 -1
3 4 -1
4 2 -1
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
#define ll long long
const int N=2e5+10,M=3e5+10;
int h[N],e[N],ne[N],w[N],idx;
int dist[N],cnt[N]; //边数
int t,n,m;
bool st[N];
void add(int a,int b,int wa)
{
e[idx]=b,ne[idx]=h[a],w[idx]=wa,h[a]=idx++;
}
bool Spfa()
{
memset(cnt,0,sizeof cnt);
memset(st,false,sizeof st);
queue<int> q;
for(int i=1;i<=n;i++) q.push(i),st[i]=true;
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>n) return true;
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
return false;
}
void solve()
{
idx=0;
memset(h,-1,sizeof h);
memset(w,0,sizeof w);
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
if(w>=0) add(u,v,w),add(v,u,w);
else add(u,v,w);
}
if(Spfa()) printf("YES\n");
else printf("NO\n");
}
int main()
{
scanf("%d",&t);
while(t--) solve();
return 0;
}