2017 ACM/ICPC 亞洲區(烏魯木齊賽區) 網絡賽 F Islands(求使有向圖成爲強聯通圖最少需要增加幾條邊)

題目鏈接:Islands
題解:使用Tarjan算法找到每個強聯通分量,此時強聯通分量內部各點是相互可以到達的,那麼我們可以考慮把每個獨立的強聯通分量當作一個個獨立的點處理。到目前爲止,如果兩個點之間有邊,但是不屬於同一個強聯通分量的話,必然的我們需要增加一條邊,明白這個之後,計算出度和入度的最大值。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
const int maxn = 1e5+10;
const int maxe = 1e6+10;
using namespace std;
int n,m;
int head[maxn];
int cnt,tot;
struct Edge{
    int u,v,next;
}e1[maxe],e2[maxe];
int dfn[maxn],low[maxn];
stack<int> S;
int instack[maxn],belong[maxn],num[maxn];
int scc,index;//scc記錄強連通分量的個數
int in[maxn],out[maxn];
void addEdge(int u,int v,Edge* e1,int& cnt){
    e1[cnt].u = u;e1[cnt].v = v;
    e1[cnt].next = head[u];head[u] = cnt++;
}

void Tarjan(int u){
    int v;
    low[u] = dfn[u] = ++index;
    S.push(u); instack[u] = 1;
    for(int i = head[u]; i != -1; i = e1[i].next){
        int v = e1[i].v;
        if(!dfn[v]){
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(instack[v]){
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u]){
        ++scc;
        while(1){
            int now = S.top();
            S.pop();
            instack[now] = 0;
            belong[now] = scc;
            num[scc]++;
            if(now == u) break;
        }
    }
}

void solve(){
    memset(dfn,0,sizeof(dfn));
    memset(num,0,sizeof(num));
    memset(instack,0,sizeof(instack));
    scc = index = 0;
    for(int i = 1; i <= n; i++){
        if(!dfn[i]) Tarjan(i);
    }
    tot = 0;
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    int u,v;
    for(int i = 0; i < cnt; i++){
        u = belong[e1[i].u];
        v = belong[e1[i].v];
        if(u != v){
            addEdge(u,v,e2,tot);
            in[v]++;
            out[u]++;
        }
    }
    int a = 0,b = 0;
    for(int i = 1; i <= scc; i++){
        if(!in[i]) a++;
        if(!out[i]) b++;
    }
    if(scc == 1) printf("0\n");
    else printf("%d\n",max(a,b));
}


int main(){
    int T;
    int u,v;
    scanf("%d",&T);
    while(T--){
        cnt = 0;
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        for(int i = 0; i < m; i++){
            scanf("%d%d",&u,&v);
            addEdge(u,v,e1,cnt);
        }
        solve();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章