hdu2767(强连通分量)一个图最少添加几条边能使得该图强连通?

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767

分析:首先找出强连通分量,然后把每个强连通分量缩成一个点,得到一个DAG。接下来,设有a个结点(别忘了,这里的每个结点对应于原图的一个强连通分量)的入度为0,b个结点的出度为0,则max{a,b}就是答案。注意特殊情况:当原图已经强连通时,答案是0而不是1。

代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <stack>

using namespace std;

const int maxn =20000+5;
int T,n,m;
int in[maxn],out[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;///scc_cnt有多少个连通分量  lowlink能追溯到的最早祖先  
/// sccno[i]=j表示i节点属于j连通分量
vector<int>G[maxn];
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 main()
{
    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<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);

        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)
            ans=0;
        printf("%d\n",ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36300700/article/details/81237439