HDU 2767 Proving Equivalences Tarjan 強連通縮點

SolarDomo發表於2016-10-11

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=2767

題意:問一個圖至少加多少條邊後能成為強連通的
我們用Tarjan處理完圖的強連通分量以後,就將每一個強連通分量縮成一個點,新的圖之後就成為一個有向無環圖
讓這個有向無環圖成為強連通的方法就是加上入度為0的點的個數 和 出度為0的點的個數取max

現在來看看怎麼連這個有向無環圖 是使這個圖強連通
對於一個出度為0 的點u 我們新增一個邊(u,v) v為入度為0的點 然後更新u,v的出入度
最後到沒有出度為0的點 或者 入度為0的點 那麼剩下的點可以隨便連圖上任何一個點
程式碼:

#include <bits/stdc++.h>
#define sf scanf
#define pf printf

using namespace std;
const int maxn = 20000 + 50;
vector<int> Adj[maxn];
stack<int> Stack;
int low[maxn],dfn[maxn],inStack[maxn],belong[maxn],ins[maxn],ous[maxn];
int TOT,Block_CNT;
void DFS(int u){
    dfn[u] = low[u] = TOT++;
    Stack.push(u);inStack[u] = 1;
    int len = Adj[u].size(),v;
    for(int i = 0;i < len;++i){
        v = Adj[u][i];
        if(dfn[v] == -1){
            DFS(v);
            low[u] = min(low[u],low[v]);
        }
        else if(inStack[v]) low[u] = min(low[u],dfn[v]);
    }

    if(low[u] == dfn[u]){
        int tmp;
        do{
            tmp = Stack.top();Stack.pop();
            inStack[tmp] = false;
            belong[tmp] = Block_CNT;
        }while(tmp != u);
        Block_CNT++;
    }
}

int main(){
    int T;sf("%d",&T);
    while(T--){
        memset(dfn,-1,sizeof dfn);
        memset(inStack,0,sizeof inStack);
        memset(ins,0,sizeof ins);
        memset(ous,0,sizeof ous);
        TOT = 1;Block_CNT = 0;
        int n,m;sf("%d %d",&n,&m);
        for(int i = 1;i <= n;++i) Adj[i].clear();
        for(int i = 0;i < m;++i){
            int u,v;sf("%d %d",&u,&v);
            Adj[u].push_back(v);
        }
        for(int i = 1;i <= n;++i)
            if(dfn[i] == -1) DFS(i);
        for(int i = 1;i <= n;++i){

            int len = Adj[i].size();
            for(int j = 0;j < len;++j){
                int v = Adj[i][j];
                if(belong[i] != belong[v]) ous[belong[i]]++,ins[belong[v]]++;
            }
        }
        int cnt_ous = 0,cnt_ins = 0;
        for(int i = 0;i < Block_CNT;++i){
            if(ins[i] == 0) cnt_ins++;
            if(ous[i] == 0) cnt_ous++;
        }
        if(Block_CNT == 1) cnt_ous = 0,cnt_ins = 0;
        pf("%d\n",max(cnt_ous,cnt_ins));
    }
}

相關文章