zoukankan      html  css  js  c++  java
  • HDU3342:判断有向图中是否存在3元环-Tarjan或拓扑排序

    题目大意:

      

    给你一个关系图,判断是否合法。每个人都有师父和徒弟,可以有很多个;

    若A是B的师父,B是C的师父,则A也算C的师父。

    不合法: 


    1) . 互为师徒;(有回路) 
     2) .你的师父是你徒弟的徒弟,或者说你的徒弟是你师父的师父。(出现回路)

    思路:


    判断有向图中是否存在回路或至少3元环; 
    此题至少有三种做法,此处更新拓扑排序的做法:

    解题方法:

    一:拓扑排序:

    1) . 统计每个点的入度;

    2) . 将入度为0的点加入队列;

    3) . 出去队首元素,将此元素所连接的点入度减一,若此后入度为0则加入队列;

    4) . 判断队列循环次数,若等于n则不存在3元环,则此关系图合法;

    题目链接:

    点击打开链接

    #include<iostream>  
    #include<cstdio>  
    #include<cstring>  
    #include<algorithm>  
    #include<cmath>  
    #include<cstdlib>  
    #include<queue>  
    #include<map>  
    #include<stack>  
    #include<vector>  
    #include<ctime>  
    using namespace std;  
    const int  N = 2005;
    const int  M = 3000005;
    int n,m;
    int tot,flag;
    int in[N],head[N];
    struct lp
    {
        int u,v,nex;
        lp(){}
        lp(int a,int b,int c):
        u(a),v(b),nex(c){}
    }cw[N];
    void add(int a,int b){
        cw[++tot]=lp(a,b,head[a]);
        head[a]=tot;
    }
    void tuopu(){
        queue<int>Q;
        while(!Q.empty())Q.pop();
        for(int i=0;i<n;++i){
            if(in[i]==0)Q.push(i);
        }
        int t=0;
        while(!Q.empty()){
            t++;
            int u=Q.front();Q.pop();
            for(int i=head[u];i!=-1;i=cw[i].nex){
                int v=cw[i].v;
                in[v]--;
                if(in[v]==0)Q.push(v);
            }
        }
        if(t==n)flag=1;
    }
    int main(int argc, char const *argv[])
    {
        int a,b;
        while(~scanf("%d%d",&n,&m)&&(n)){
            memset(in,0,sizeof(in));
            tot=-1;
            memset(head,-1,sizeof(head));
            for(int i=0;i<m;++i){
                scanf("%d%d",&a,&b);
                add(a,b);
                in[b]++;
            }
            flag=0;
            tuopu();
            if(flag)printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    View Code

    二:Tarjan:

    #include<iostream>  
    #include<cstdio>  
    #include<cstring>  
    #include<algorithm>  
    #include<cmath>  
    #include<cstdlib>  
    #include<queue>  
    #include<map>  
    #include<stack>  
    #include<vector>  
    #include<ctime>  
    using namespace std;  
    const int  N = 105;
    const int  M = 3000005;
    int n,tot,flag,idex;
    int head[N],vis[N];
    int low[N],dfn[N];
    int qltNum;
    int qltMap[N];
    stack<int>st;
    struct lp{
        int to,nex;
        lp(){}//构造函数
        lp(int a,int b):
        to(a),nex(b){}
    }cw[N*N];
    void add(int a,int b){
        cw[++tot]=lp(b,head[a]);
        head[a]=tot;
    }
    void dfs(int u,int fa){
        dfn[u]=low[u]=++idex;
        vis[u]=1;
        st.push(u);
        int v;
        for(int i=head[u];i!=-1;i=cw[i].nex){
            v=cw[i].to;
            if(v==fa){
                flag=1;
                break;
            }
            if(!vis[v]){
                dfs(v,u);
                if(flag)return;
                low[u]=min(low[u],low[v]);
            }else if(vis[v]==1){
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){//缩点
            qltNum++;
            int t=0;
            do{
                t++;
                v=st.top();st.pop();
                vis[v]=2;
                qltMap[v]=qltNum;
                if(t>=3){
                    flag=1;
                    return;
                }
            }while(v!=u);
            //cout<<t<<"
    ";
        }
    }
    void tarjan(){
        for(int i=1;i<=n;++i){
            if(!vis[i]){
                dfs(i,-1);
            }
            if(flag)return;
        }
    }
    void init(){//初始化
        while(!st.empty())st.pop();
        qltNum=idex=flag=0;
        tot=-1;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(qltMap,0,sizeof(qltMap));
    }
    int main(int argc, char const *argv[]){
        int a,b,m;
        while(~scanf("%d%d",&n,&m)&&(n)){
            init();
            memset(head,-1,sizeof(head));
            for(int i=0;i<m;++i){
                scanf("%d%d",&a,&b);
                a++,b++;
                add(a,b);
            }
            tarjan();
            if(flag)printf("NO
    ");
            else printf("YES
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Magic-Club第六天
    .net工具类——文件操作
    .net工具类——HTML处理
    .net工具类——随机生成
    .net工具类——删除最后结尾的一个逗号
    .net工具类——分割字符串
    .net工具类——对象转换处理
    .net扩展方法——其他(科学计数法、ToDictionary 去重、List<Guid>转为List<Guid?>)
    .net扩展方法——类型转换
    『Linux学习笔记』7. 管道和过滤器 -- pipe
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/8796575.html
Copyright © 2011-2022 走看看