zoukankan      html  css  js  c++  java
  • HDU1269(有向图缩点模板题)

    迷宫城堡

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 11070    Accepted Submission(s): 4948


    Problem Description
    为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
     
    Input
    输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
     
    Output
    对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
     
    Sample Input
    3 3
    1 2
    2 3
    3 1
    3 3
    1 2
    2 3
    3 2
    0 0
     
    Sample Output
    Yes
    No
    有向图缩点模板题
    模板1:kosaraju
    #include"cstdio"
    #include"cstring"
    #include"vector"
    using namespace std;
    const int MAXN=10005;
    vector<int> G[MAXN];
    vector<int> rG[MAXN];
    vector<int> vs;
    int V,E;
    int vis[MAXN];
    inline int max(int a,int b)
    {
        return a > b? a: b;
    }
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=0;i<G[u].size();i++)
            if(!vis[G[u][i]])    dfs(G[u][i]);
        vs.push_back(u);
    }
    void rdfs(int u)
    {
        vis[u]=1;
        for(int i=0;i<rG[u].size();i++)    
            if(!vis[rG[u][i]])    rdfs(rG[u][i]);
    }
    bool scc()
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=V;i++)
            if(!vis[i]) dfs(i);
        memset(vis,0,sizeof(vis));
        int k=0;
        for(int i=vs.size()-1;i>=0;i--)
            if(!vis[vs[i]])
            {
                rdfs(vs[i]);
                k++;
                if(k>1)    return false;
            }
        return true;
    }
    int main()
    {
        while(scanf("%d%d",&V,&E)!=EOF&&V)
        {
            vs.clear();
            for(int i=1;i<=V;i++)
            {
                G[i].clear();
                rG[i].clear();
            }
            for(int i=0;i<E;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                G[u].push_back(v);
                rG[v].push_back(u);
            }
        
            if(scc())
            {
                printf("Yes
    ");
            }
            else
            {
                printf("No
    ");
            }
        }
            
        return 0;
    }

    模板2:tarjan

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int MAXN=10005;
    vector<int> mp[MAXN];
    int n,m;
    int dfn[MAXN],low[MAXN],time;
    int stack[MAXN],top;
    bool ins[MAXN];
    int cnt=0;
    void tarjan(int u)
    {
        dfn[u]=low[u]=++time;
        stack[top++]=u;
        ins[u]=true;
        for(int i=0;i<mp[u].size();i++)
        {
            int v=mp[u][i];
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(ins[v])    low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            int v;
            cnt++;
            do{
                v=stack[--top];
                ins[v]=false;
            }while(u!=v);
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n==0&&m==0)    
                break;
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(ins,false,sizeof(ins));
            time=0;
            top=0;
            cnt=0;    
            for(int i=1;i<=n;i++)
                mp[i].clear();
            for(int i=0;i<m;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                mp[u].push_back(v);
            }
            
            for(int i=1;i<=n;i++)
            {
                if(!dfn[i])
                {
                    tarjan(i);
                }
            }
            
            if(cnt==1)
                printf("Yes
    ");
            else
                printf("No
    ");
        }
    }

    该题目也可用并查集做。

    #include"cstdio"
    #include"cstring"
    using namespace std;
    const int MAXN=100005;
    int V,E;
    int par[2][MAXN];//par[0][MAXN]记录正向边,par[1][MAXN]记录反向边 
    int fnd(int x,int type)
    {
        if(par[type][x]==x)
        {
            return x;
        }
        return par[type][x]=fnd(par[type][x],type);
    }
    void unite(int x,int y)
    {
        if(x>1)    par[0][x]=fnd(y,0);//将结点1作为根结点 
        if(y>1) par[1][y]=fnd(x,1);
    }
    bool judge()
    {
        for(int i=2;i<=V;i++)
            if(fnd(i,0)!=1||fnd(i,1)!=1)    return false;//若所有结点(除1)沿正向边均能到达1结点且将边反向后也均能到达1结点,那么改图为强连通图 
        return true;
    }
    int main()
    {
        while(scanf("%d%d",&V,&E)!=EOF&&V)
        {
            for(int i=1;i<=V;i++) par[0][i]=par[1][i]=i;
            for(int i=0;i<E;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                unite(u,v);
            }
            if(judge())    printf("Yes
    ");
            else    printf("No
    ");
        }
        
        return 0;
    }
     
  • 相关阅读:
    (Java实现) 删数问题
    (Java实现) 车站
    (Java实现) 活动选择
    (Java实现) 过河卒
    (Java实现) 美元汇率
    (Java实现) 零件分组
    (Java实现) 图的m着色问题
    (Java实现) 数塔问题
    Java实现 蓝桥杯VIP 算法训练 数的划分
    DirectUI的消息流转
  • 原文地址:https://www.cnblogs.com/program-ccc/p/5170566.html
Copyright © 2011-2022 走看看