HDU 2767 Proving Equivalences【强连通分量+缩点】

题意: 在有 n 个节点的有向图中 有 m 条边,问最少需要增加多少条边可以将原图变成一个强连通图。

分析: 因为图中每个环都满足强连通的性质,可以用强连通分量的算法将原图中的环进行染色缩点。

          缩点的最大好处在于把一个杂乱无章的有向图变成一个有向无环图,而在有向无环图中,有两种点

          比较特殊: 一种是入度为 0 的点,另一种是 出度为 0 的点。  

          题目问要增加多少条边使得原图变成强连通图,其实只要知道在树根个叶子之间加多少条边,假如 r

          为根的个数,  g 为叶子的个数,答案即为max(r,g)。

          特殊情况是当缩点之后只有一个点时,答案为 0。

code:

View Code
#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
const int maxn=20002;
struct node
{
    int to;
    int next;
}q[60000];
int head[maxn];
int tot;
void add(int s,int u)
{
    q[tot].to=u;
    q[tot].next=head[s];
    head[s]=tot++;
}
bool ins[maxn];
int color[maxn];
int dfn[maxn],low[maxn],stack[maxn];
int ti,sn,top;
void tarjan(int u)
{
    dfn[u]=low[u]=++ti;
    stack[++top]=u;
    ins[u]=true;
    int i,k;
    for(i=head[u];i;i=q[i].next)
    {
        k=q[i].to;
        if(dfn[k]==0)
        {
            tarjan(k);
            if(low[k]<low[u])
                low[u]=low[k];
        }
        else if(ins[k]&&dfn[k]<low[u])
            low[u]=dfn[k];
    }
    if(dfn[u]==low[u])
    {
        sn++;
        do
        {
            k=stack[top--];
            ins[k]=false;
            color[k]=sn;    // 强连通分量染色
        }
        while(k!=u);
    }
}
int id[maxn],od[maxn];
int main()
{
    int t,i,j,k,a,b,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        tot=1;
        top=-1;
        sn=ti=0;
        clr(low);
        clr(dfn);
        clr(ins);
        clr(head);
    
        while(m--)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        for(i=1;i<=n;i++)
            if(dfn[i]==0)
                tarjan(i);
        if(sn==1)
            printf("0\n");
        else 
        {
            clr(id);
            clr(od);
            int in=0,out=0;
            for(i=1;i<=n;i++)
                for(j=head[i];j;j=q[j].next)
                {
                    k=q[j].to;
                    if(color[i]!=color[k])
                    {
                        id[color[k]]++;
                        od[color[i]]++;
                    }
                }
            for(i=1;i<=sn;i++)
            {
                if(id[i]==0)
                    in++;
                if(od[i]==0)
                    out++;
            }
            printf("%d\n",in>out?in:out);
        }
    }
    return 0;
}

 

        

posted @ 2012-07-15 21:17  'wind  阅读(322)  评论(0编辑  收藏  举报