zoukankan      html  css  js  c++  java
  • UVALive-4287 Proving Equivalences (有向图的强连通分量)

    题目大意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导。

    题目分析:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图。找出所有的强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG。设出度为0的大节点个数为a,入度为0的大节点个数为b,则答案就是max(a,b)。为什么是这样呢?因为要使等价证明前进下去,每个大节点的出度和入度都必须不能是0。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<vector>
    # include<stack>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    
    const int maxn=20005;
    int n,m,low[maxn],pre[maxn],sccno[maxn],in[maxn],out[maxn],dfs_cnt,scc_cnt;
    stack<int>S;
    vector<int>G[maxn];
    
    void dfs(int u)
    {
        low[u]=pre[u]=++dfs_cnt;
        S.push(u);
        for(int i=0;i<G[u].size();++i){
            int v=G[u][i];
            if(!pre[v]){
                dfs(v);
                low[u]=min(low[u],low[v]);
            }else if(!sccno[v])
                low[u]=min(pre[v],low[u]);
        }
        if(low[u]==pre[u]){
            ++scc_cnt;
            while(1){
                int x=S.top();
                S.pop();
                sccno[x]=scc_cnt;
                if(x==u)
                    break;
            }
        }
    }
    
    void findScc()
    {
        memset(low,0,sizeof(low));
        memset(pre,0,sizeof(pre));
        memset(sccno,0,sizeof(sccno));
        dfs_cnt=scc_cnt=0;
        for(int i=0;i<n;++i)   if(!pre[i])
            dfs(i);
    }
    
    void read()
    {
        int a,b;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i)  G[i].clear();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            --a,--b;
            G[a].push_back(b);
        }
    }
    
    void solve()
    {
        for(int i=1;i<=scc_cnt;++i)
            in[i]=out[i]=1;///先假设所有分量的出度和入度都是0;
        for(int i=0;i<n;++i)
            for(int j=0;j<G[i].size();++j)
                if(sccno[i]!=sccno[G[i][j]])
                    out[sccno[i]]=in[sccno[G[i][j]]]=0;///如果i和G[i][j]不在一个分量内,则其对应的出度和入度不是0;
        int a=0,b=0;
        for(int i=1;i<=scc_cnt;++i){
            if(in[i])   ++a;
            if(out[i])  ++b;
        }
        int ans=max(a,b);
        if(scc_cnt==1)
            ans=0;
        printf("%d
    ",ans);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            read();
            findScc();
            solve();
        }
        return 0;
    }
    

      

  • 相关阅读:
    Add Two Numbers
    Reverse Linked List II
    Reverse Linked List
    Remove Duplicates from Sorted List
    Remove Duplicates from Sorted List II
    Partition List
    Intersection of Two Linked Lists
    4Sum
    3Sum
    2Sum
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4898742.html
Copyright © 2011-2022 走看看