• 洛谷P3385判负环——spfa


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

    两种方法,dfs和bfs;

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

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

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

    #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
    ",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
    ");
            else printf("N0
    ");
        }
        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
    ");
            else printf("N0
    ");
        }
        return 0;
    }
  • 相关阅读:
    HTTP方法(转)(学习基础)
    正则表达式 学习手记 111221
    原型模式 学习手记
    分布式事务 MSDTC配置
    Ibatis.Net 学习手记二 缓存
    IIS 7.0 部署MVC
    事务与分布式事务
    Ibatis+MVC 3.0 开发手记
    Ibatis.Net 学习手记一 简单的Demo
    简单工厂 学习手记
  • 原文地址:https://www.cnblogs.com/Zinn/p/8955889.html
Copyright © 2020-2023  润新知