题目:https://www.luogu.org/problemnew/show/P3385

两种方法,dfs和bfs;

一开始写的dfs,要把dis数组初值赋成0,这样从一个连着负边的点开始搜;

在一个负环上,一定会有一个点,从它开始绕环走,dis值一直为负,根据这个找环;

但是数据太强了,过不了:

洛谷P3385判负环——spfa_数组洛谷P3385判负环——spfa_ios_02
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const MAXN=4005,MAXM=12005;
int T,n,m,head[MAXN],ct,dis[MAXN];
bool vis[MAXN],f;
struct N{
    int to,next,w;
    N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
}edge[MAXM];
void add(int x,int y,int z)
{
    edge[++ct]=N(y,head[x],z);head[x]=ct;
}
int rd()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
void dfs(int x)
{
    if(f)return;
    vis[x]=1;
    for(int i=head[x],u;i;i=edge[i].next)
    {
        u=edge[i].to;
        if(f)return;
        if(dis[u]>dis[x]+edge[i].w)
        {
//            printf("x=%d u=%d vis[u]=%d\n",x,u,vis[u]);
            if(vis[u])
            {
                f=1;return;
            }
            dis[u]=dis[x]+edge[i].w;
            dfs(u);
            if(f)return;
        }
    }
    vis[x]=0;//!
}
int main()
{
    T=rd();
    while(T--)
    {
        n=rd();m=rd();
        ct=0;f=0;
        memset(head,0,sizeof head);
        for(int i=1,x,y,z;i<=m;i++)
        {
            x=rd();y=rd();z=rd();
            add(x,y,z);
            if(z>=0)add(y,x,z);
        }
        memset(vis,0,sizeof vis);
        memset(dis,0,sizeof dis);
        for(int i=1;i<=n;i++)
        {
            dfs(i);
            if(f)break;
        }
        if(f)printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}
dfs

于是用bfs,根据最短路边数来判断,若边数>=n则有负环;

bfs的话还有一种判断方式,是根据被松弛次数,若>=n则有负环,但不如上面那个优;

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
//queue<int>q;
int const MAXN=4005,MAXM=12005,inf=4000;
int T,n,m,head[MAXN],ct,dis[MAXN],cnt[MAXN],que[MAXN],h,t;
bool vis[MAXN];
struct N{
    int to,next,w;
    N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
}edge[MAXM];
inline void add(int x,int y,int z){edge[++ct]=N(y,head[x],z);head[x]=ct;}
inline int rd()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline bool spfa()
{
//    while(q.size())q.pop();
    memset(que,0,sizeof que);h=0;t=0;
    memset(dis,0x3f,sizeof dis);
    memset(cnt,0,sizeof cnt);
    memset(vis,0,sizeof vis);
//    q.push(1);
    vis[1]=1;dis[1]=0;que[t]=1;
//    while(q.size())
    while(h!=t+1)
    {
//        int x=q.top();vis[x]=0;q.pop();
        int x=que[h++];vis[x]=0;
        if(h==inf)h=0;
        for(int i=head[x],u;i;i=edge[i].next)
            if(dis[u=edge[i].to]>dis[x]+edge[i].w)
            {
                cnt[u]=cnt[x]+1;
                if(cnt[u]>=n)return 1;
                dis[u]=dis[x]+edge[i].w;
//                if(!vis[u])vis[u]=1,q.push(u);
                if(!vis[u])
                {
                    vis[u]=1;
                    t++;
                    if(t==inf)t=0;
                    que[t]=u;
                }
            }
    }
    return 0;
}
int main()
{
    T=rd();
    while(T--)
    {
        n=rd();m=rd();
        ct=0;
        memset(head,0,sizeof head);
        for(int i=1,x,y,z;i<=m;i++)
        {
            x=rd();y=rd();z=rd();
            add(x,y,z);
            if(z>=0)add(y,x,z);
        }
        if(spfa())printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}