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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章