SPFA判负环

Posted wxl-ezio

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPFA判负环相关的知识,希望对你有一定的参考价值。

原理很简单,SPFA可以多次入队,那么如果一个点入队的次数比点的总数还要多,或是起点入队两次,那么这个图肯定存在负环

  • 例题

Luogu P3385 【模板】负环

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct zzz{
    int f,
        t,
        len,
        nex;
}e[10001*4];
int head[2001],tot;
inline void add(int x,int y,int z)
{
    e[++tot].f=x;
    e[tot].t=y;
    e[tot].len=z;
    e[tot].nex=head[x];
    head[x]=tot;
}
inline int read()
{
    int k=0,f=1; char c=getchar();
    for(;c>'9'||c<'0';c=getchar())
      if(c=='-')  f=-1;
    for(;c<='9'&&c>='0';c=getchar())
      k=(k<<3)+(k<<1)+c-48;
    return k*f;

}
bool SPFA(int n)
{
    queue <int> q; int flag[2001]={0};
    int dis[2001]; memset(dis,2,sizeof(dis));
    bool vis[2001]; memset(vis,0,sizeof(vis));
    dis[1]=0; q.push(1); vis[1]=1;
    while(!q.empty())
    {
        int k=q.front(); q.pop(); vis[k]=0;
        for(int i=head[k];i;i=e[i].nex)
        {
            int to=e[i].t;
            if(dis[to]>dis[k]+e[i].len)
            {
                dis[to]=dis[k]+e[i].len;
                if(!vis[to])
                {    
                    flag[to]++;
                    if(flag[to]>n)
                      return 1;
                    q.push(to);
                    vis[to]=1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    int t=read();
    while(t--)
    {
        tot=0; memset(head,0,sizeof(head));
        int n=read(),m=read();
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read();
            if(z<0)
              add(x,y,z);
            else
              add(x,y,z), add(y,x,z);
        }
        if(SPFA(n))
          printf("YE5
");
        else
          printf("N0
");
    }

    return 0;
}

Luogu P2850 [USACO06DEC]虫洞Wormholes

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read()
{
    int k=0; char c=getchar();
    for(;!isdigit(c);) c=getchar();
    for(;isdigit(c);c=getchar())
      k=(k<<3)+(k<<1)+c-48;
    return k;
}
struct zzz{
    int f,
        t,
        len,
        nex;
}e[3000*2]; int head[501*2],tot;
inline void add(int x,int y,int z)
{
    e[++tot].f=x;
    e[tot].t=y;
    e[tot].len=z;
    e[tot].nex=head[x];
    head[x]=tot;
}
int dis[501*2],sum[501*2]; bool vis[501*2],flag;
queue <int> q;
int main()
{
    int t; t=read();
    while(t--)
    {
        memset(head,0,sizeof(head)); tot=0,flag=0;
        memset(sum,0,sizeof(sum));
        int n,m,w; n=read(),m=read(),w=read();
        for(int i=1;i<=m;i++)
        {
            int x,y,z; x=read(),y=read(),z=read();
            add(x,y,z); add(y,x,z);
        }
        for(int i=1;i<=w;i++)
        {
            int x,y,z; x=read(),y=read(),z=read();
            add(x,y,-z);
        }
        memset(dis,2,sizeof(dis));
        q.push(1); dis[1]=0; vis[1]=1;
        while(!q.empty())
        {
            int k=q.front(); q.pop(); vis[k]=0;
            for(int i=head[k];i;i=e[i].nex)
            {
                if(dis[e[i].t]>dis[k]+e[i].len)
                {
                    dis[e[i].t]=dis[k]+e[i].len;
                    if(!vis[e[i].t])
                    {
                        vis[e[i].t]=1;
                        q.push(e[i].t);
                        sum[e[i].t]++;
                        if(sum[e[i].t]>n)
                        {
                            flag=1; break;
                        }
                    }
                }
            }
            if(flag)
              break;
        }
        if(flag)
          printf("YES
");
        else
          printf("NO
");
    }
    
    
    
    
    return 0;
}

以上是关于SPFA判负环的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3259 Wormholes(SPFA判负环)

SPFA判负环

洛谷P3385 模板负环 DFS-SPFA 判负环 图论

poj3259 Wormholes(spfa判负环)

SPFA的BFS与DFS实现及判负环问题

模板SPFA判负环