• 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;
    }
    

      

  • 相关阅读:
    一系列视频教程 收藏
    生成一个4位整数
    spring 实现定时任务
    判断字符串是否包含汉字
    pmd代码安全扫描工具
    IntelliJ IDEA
    李小龙传奇
    checkmarx使用笔记、原理
    pmd 使用笔记
    Mysql的安装(视频+部分视频截图)
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4898742.html
Copyright © 2020-2023  润新知