zoukankan      html  css  js  c++  java
  • [luogu3385]dfs_spfa判负环模板

    解题关键:模板保存。

    判负环不需要memset dis数组,因为已经更新过得d数组一定小于0,如果当前点可以更新d,说明d更小,有可能继续扩大负环,所以继续更新;如果比d[v]大,则不可能继续更新负环,所以直接终止。

     有向图只扫一个点貌似不可以。。。bfs_spfa的时候一定注意,但dfs_spfa一定可以。

    dfs过不了这道题,因为必须经过1这个点,或许d不置0可以,但会超时?

    有向图可以使用拓扑排序找环。

    1、dfs

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxm=111110;
    const int maxn=20020;
    int head[maxn],tot,n,m;
    struct edge{
        int to;
        int w;
        int nxt;
    }e[maxm];
    void add_edge(int u,int v,int w){
        e[tot].w=w;
        e[tot].to=v;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    bool vis[maxn];
    int d[maxn];
    //
    bool dfs_spfa(int u){
        vis[u]=1;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(d[v]>d[u]+e[i].w){
                d[v]=d[u]+e[i].w;
                if(vis[v]||dfs_spfa(v)) return 1;
            }
        }
        vis[u]=0;
        return 0;
    }
    int main(){
        int a,b,c,T;
        scanf("%d",&T);
        while(T--){
            tot=0;
            memset(head,-1,sizeof head);
            memset(vis,0,sizeof vis);
            memset(d,0,sizeof d);
            scanf("%d%d",&n,&m);
            for(int i=0;i<m;i++){//注意为双向边
                scanf("%d%d%d",&a,&b,&c);
                if(c<0) add_edge(a,b,c);
                else add_edge(a,b,c),add_edge(b,a,c);
            }
            bool flag=false;
            for(int i=1;i<=n;i++){
                if(dfs_spfa(i)){
                    flag=true;
                    break;
                }
            }
            if(flag) puts("YE5");
            else puts("N0");
        }
        return 0;
    }

     2、bfs_spfa

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxm=11111;
    const int maxn=5000;
    int head[maxn],tot,n,m,cnt[maxn],w;
    struct edge{
        int to;
        int w;
        int nxt;
    }e[maxm];
    void add_edge(int u,int v,int w){
        e[tot].w=w;
        e[tot].to=v;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    
    bool vis[maxn];
    queue<int>que;//队列是点的队列
    int d[maxn];
    bool spfa(int s){
        memset(cnt,0,sizeof cnt);
        fill(d+1,d+n+1,inf);
        memset(vis,0,sizeof vis);
        while(!que.empty()) que.pop();
        que.push(s);
        vis[s]=true;
        d[s]=0;
        while (!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=false;
            for (int i=head[u];i!=-1;i=e[i].nxt){
                int v=e[i].to;
                int w=e[i].w;
                if (d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    cnt[v]=cnt[u]+1;
                    if(cnt[v]>n) return true;
                    if (!vis[v]){
                        vis[v]=true;
                        que.push(v);
                    }
                }
            }
        }
        return false;
    }
    int main(){
        int a,b,c,T;
        scanf("%d",&T);
        while(T--){
            tot=0;
            memset(head,-1,sizeof head);
            memset(vis,0,sizeof vis);
            memset(d,0,sizeof d);
            scanf("%d%d",&n,&m);
            for(int i=0;i<m;i++){//注意为双向边
                scanf("%d%d%d",&a,&b,&c);
                add_edge(a,b,c);
                if(c>=0)add_edge(b,a,c);
            }
            if(spfa(1)) puts("YE5");
            else puts("N0");
        }
        return 0;
    }

    3、bfs_spfa(num>n)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxm=11111;
    const int maxn=5000;
    int head[maxn],tot,n,m,num[maxn],w;
    struct edge{
        int to;
        int w;
        int nxt;
    }e[maxm];
    void add_edge(int u,int v,int w){
        e[tot].w=w;
        e[tot].to=v;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    
    bool vis[maxn];
    queue<int>que;//队列是点的队列
    int d[maxn];
    bool spfa(int s){
        memset(num,0,sizeof num);
        fill(d+1,d+n+1,inf);
        memset(vis,0,sizeof vis);
        while(!que.empty()) que.pop();
        que.push(s);
        vis[s]=true;
        d[s]=0;
        while (!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=false;
            for (int i=head[u];i!=-1;i=e[i].nxt){
                int v=e[i].to;
                int w=e[i].w;
                if (d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    if (!vis[v]){
                        vis[v]=true;
                        que.push(v);//hash一下,可判断是否存在负环
                        num[v]++;
                        if(num[v]>n) return true;
                    }
                }
            }
        }
        return false;
    }
    int main(){
        int a,b,c,T;
        scanf("%d",&T);
        while(T--){
            tot=0;
            memset(head,-1,sizeof head);
            memset(vis,0,sizeof vis);
            memset(d,0,sizeof d);
            scanf("%d%d",&n,&m);
            for(int i=0;i<m;i++){//注意为双向边
                scanf("%d%d%d",&a,&b,&c);
                add_edge(a,b,c);
                if(c>=0)add_edge(b,a,c);
            }
            if(spfa(1)) puts("YE5");
            else puts("N0");
        }
        return 0;
    }
     
  • 相关阅读:
    codeforces_346A Alice and Bob(数学)
    POJ_2533 Frogger 最小瓶颈路
    hdu1205_吃糖果
    POJ_2503 Babelfish 字典树
    在PC上登录多个微信账号
    查看百度云用户的分享文件
    QQ邮箱收不到ins发的验证码
    试用Fakeapp
    为什么使用网易邮箱
    插入央视网站视频
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/10353439.html
Copyright © 2011-2022 走看看