• UVALive 4287 Proving Equivalence (强连通分量)


    把证明的关系看出一张图,最终就是要所有的点都在至少一个环中。环的判断和度数有关。

    用tarjan找强连通分量,在一个强连通分量点已经等价缩点以后形成一个DAG,计算入度为0的点数a,

    出度为0的b,取其中大的一个。特判强连通分量数为1的情况。

    看懂tarjan算法以后还是比较简单的

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e4+5;
    const int maxm = 5e4+5;
    
    int head[maxn],nxt[maxm],to[maxm],ecnt;
    void addEdge(int u,int v)
    {
        nxt[ecnt] = head[u];
        to[ecnt] = v;
        head[u] = ecnt++;
    }
    
    void initGraph(int n)
    {
        memset(head,-1,sizeof(int)*(n+1)); ecnt = 0;
    }
    
    int sccno[maxn],pre[maxn],low[maxn],dfs_clock,scc_cnt;
    stack<int> stk;
    
    void tarjan(int u)
    {
        pre[u] = low[u] = ++dfs_clock;
        stk.push(u);
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(!pre[v]){
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }else if(!sccno[v]){
                low[u] = min(low[u],pre[v]);
            }
        }
        if(low[u] == pre[u]){
            scc_cnt++;
            while(stk.size()){
                int x = stk.top(); stk.pop();
                sccno[x] = scc_cnt;
                if(x == u) break;
            }
        }
    }
    
    void find_scc(int n)
    {
        memset(pre,0,sizeof(int)*(n+1));
        memset(sccno,0,sizeof(int)*(n+1));
        scc_cnt = dfs_clock = 0;
        for(int i = 0; i < n; i++){
            if(!pre[i]) tarjan(i);
        }
    }
    
    int ind[maxn],outd[maxn];
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int T; scanf("%d",&T);
        while(T--){
            int n,m; scanf("%d%d",&n,&m);
            initGraph(n);
            for(int i = 0; i < m; i++){
                int u,v; scanf("%d%d",&u,&v);
                addEdge(u-1,v-1);
            }
            find_scc(n);
            if(scc_cnt == 1) {
                printf("0
    "); continue;
            }
            for(int i = 1; i <= scc_cnt; i++) ind[i] = outd[i] = 0;
            for(int u = 0; u < n; u++){
                for(int i = head[u]; ~i; i = nxt[i]){
                    int v = to[i];
                    if(sccno[u] != sccno[v]) outd[sccno[u]]++,ind[sccno[v]]++;
                }
            }
            int a = 0,b = 0;
            for(int i = 1; i <= scc_cnt; i++){
                if(!outd[i]) b++;
                if(!ind[i]) a++;
            }
            printf("%d
    ",max(a,b));
        }
        return 0;
    }
  • 相关阅读:
    JDK的命令详解
    聊天室java socket
    怎么实现利用Java搜索引擎收集网址的程序
    Hibernate实现对多个表进行关联查询
    如何学好J2ME?
    谈谈Java工程师应该具有的知识
    【经营智慧】005.眼光盯着未来
    【成功智慧】002.对任何小事都不要掉以轻心
    【经营智慧】008.要想赚钱,就得打破既有的成见
    【思维智慧】004.砸碎障碍的石头,把它当做钥匙
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4776959.html
Copyright © 2020-2023  润新知