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\n", ans);    
}
int main(int argc, char** argv) 
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        init();
        input();
        solve();
    }
    return 0;
}
View Code

 

posted @ 2016-03-15 16:18  zhaop  阅读(174)  评论(0编辑  收藏  举报