HDU 3836 Equivalent Sets【强连通分量】

题意: 知道了一些集合的包含关系,问至少还要知道多少个包含关系才能证明这些集合是相互等价的。

分析: 看出是强连通分量的模型就不难了。  最少加多少对关系使得每个集合等价,相当于在图中加入一些边,使得原图任意两个点互达即强连通,

           找出这个边数即可。

#include<stdio.h>
#include<string.h>
#define maxn 20002
#define clr(x)memset(x,0,sizeof(x))
struct node
{
    int to,next;
}e[1000000];
int tot;
int head[maxn];
void add(int s,int u)
{
    e[tot].to=u;
    e[tot].next=head[s];
    head[s]=tot++;
}
int top,ti,sn;
int dfn[maxn];
int low[maxn];
int col[maxn];
int stack[maxn];
bool ins[maxn];
void tarjan(int u)
{
    dfn[u]=low[u]=++ti;
    stack[++top]=u;
    ins[u]=true;
    int i,k;
    for(i=head[u];i;i=e[i].next)
    {
        k=e[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;
            col[k]=sn;
        }while(k!=u);
    }
}
int id[maxn];
int od[maxn];
int main()
{
    int n,m,i,j;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int a,b;
        tot=1;
        ti=0;
        sn=0;
        top=0;
        clr(head);
        clr(low);
        clr(dfn);
        clr(col);
        clr(ins);
        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=e[j].next)
                {
                    int k=e[j].to;
                    if(col[i]!=col[k])
                    {
                        id[col[k]]++;
                        od[col[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-09-12 23:07  'wind  阅读(201)  评论(0编辑  收藏  举报