2017 烏魯木齊賽區網絡賽 Islands(【點強連通問題】【縮點+點強連通分量】)

題目鏈接:https://nanti.jisuanke.com/t/16955
【中文題意】給你一個有向圖,然後讓你加最少的邊使得全圖強連通(即從任意一個點出發,可以到達剩餘的所有點)。
【思路分析】非常經典的板子題。先找強連通分量,然後縮點後求邊的條數。
【AC代碼】

#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
#define maxn 10005

vector<int>G[maxn];

int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,n,m;
stack<int>S;
void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    S.push(u);
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u]=min(lowlink[u],pre[v]);
        }
    }
    if(lowlink[u]==pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x=S.top();
            S.pop();
            sccno[x]=scc_cnt;
            if(x==u)break;
        }
    }
}

void find_scc(int n)
{
    dfs_clock = scc_cnt = 0;
    memset(sccno, 0, sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i = 0; i < n ; i++)
    {
        if(!pre[i])dfs(i);
    }
}

int in[maxn],out[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)G[i].clear();
        for(int i=0; i<m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            u--;
            v--;
            G[u].push_back(v);
        }
        find_scc(n);
        //printf("%d***\n",scc_cnt);
        /*for(int i=0; i<n; i++)
        {
            printf("%d+++\n",sccno[i]);
        }*/
        for(int i=1; i<=scc_cnt; i++)
        {
            in[i]=out[i]=1;
        }
        for(int u=0; u<n; u++)
        {
            for(int i=0; i<G[u].size(); i++)
            {
                int v=G[u][i];
                if(sccno[u]!=sccno[v])
                {
                    in[sccno[v]]=out[sccno[u]]=0;
                }
            }
        }
        int a = 0,b=0;
        for(int i=1; i<=scc_cnt; i++)
        {
            if(in[i])a++;
            if(out[i])b++;
        }
        int ans = max(a,b);
        if(scc_cnt==1)
        {
            printf("0\n");
        }
        else
        {
            printf("%d\n",ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章