zoukankan      html  css  js  c++  java
  • HD2767Proving Equivalences(有向图强连通分量+缩点)

    题目链接

    题意:有n个节点的图,现在给出了m个边,问最小加多少边是的图是强连通的

    分析:首先找到强连通分量,然后把每一个强连通分量缩成一个点,然后就得到了一个DAG。接下来,设有a个节点(每个节点对应一个强连通分量)的入度为0,b个节点的出度为0,然后取ab最大的就行了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <stack>
    #include <algorithm>
    using namespace std;
    const int Max = 20000 + 5;
    vector<int> g[Max];
    int low[Max], dfn[Max];
    stack<int> st;
    int scc_cnt, dfs_clock, sccno[Max]; //scc_cnt强连通分量个数,sccno[x]表示x属于第几个强连通分量
    int in0[Max], out0[Max];
    int n, m;
    int Min(int x, int y)
    {
        return x > y ? y : x;
    }
    void init()
    {
        for(int i = 0; i <= n; i++)
            g[i].clear();
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(sccno, 0, sizeof(sccno));
        while(!st.empty())
            st.pop();
        dfs_clock = scc_cnt = 0;
    } 
    void input()
    {
        int u, v;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
        }
    }
    void dfs(int u)
    {
        low[u] = dfn[u] = ++dfs_clock;
        st.push(u);
        int len = g[u].size();
        for(int i = 0; i < len; i++)
        {
            int v = g[u][i];
            if(!dfn[v])
            {
                dfs(v);
                low[u] = Min(low[u], low[v]);
            }
            else if(!sccno[v])
            {
                low[u] = Min(low[u], dfn[v]);
            }
        }
    //构成一个环就成了强连通分量了
        if(low[u] == dfn[u])
        {
            scc_cnt++;
            while(!st.empty())
            {
                int x = st.top();
                st.pop();
                sccno[x] = scc_cnt;
                if(x == u)
                    break;
            }
        }
    }
    void solve()
    {
        for(int i = 1; i <= n; i++)
        {
            if(!dfn[i])
                dfs(i);
        }
        memset(in0, 0, sizeof(in0));
        memset(out0, 0, sizeof(out0));
        for(int i = 1; i <= n; i++)
        {
            int len = g[i].size();
            for(int j = 0; j < len; j++)
            {
                int v = g[i][j];
                if(sccno[i] != sccno[v])
                {
                    out0[sccno[i]]++;
                    in0[sccno[v]]++;
                }
            }
        }
        int a = 0, b = 0;
        for(int i = 1; i <= scc_cnt; i++)
        {
           if(!in0[i]) 
               a++;
            if(!out0[i])
                b++;
        }
        int ans = max(a, b);;
        if(scc_cnt == 1) //如果本身就是连通的输出0
            ans = 0;
        printf("%d
    ", ans);    
    }
    int main(int argc, char** argv) 
    {
        int t;
        scanf("%d", &t);
        while(t--)
        {
            init();
            input();
            solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Java1:Chapter2
    Java1:Chapter1
    Java1:Chapter11
    Java1:Chapter8
    Java1:Chapter6
    Android day 03
    Android day02
    Android day01
    二进制文件的读写
    字符流
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5279953.html
Copyright © 2011-2022 走看看