[HDU] 3836 Equivalent Sets

题目大意为给定一张有向图,求加多少条边之后整个图是一张强连通分量。

思路大致是:先将图中的强连通分量缩点,使得图变成一张无环图,这个时候图上剩余k1个出度为0的点和k2个入度为0的点,将出度为0的点连一条有向边到入度为0的点,此时形成一个环,这个环是一个强连通分量,可以再缩成一个点,当图中只剩一个点的时候,就完成了任务。显而易见的是最大只要连接max{k1,k2}条边,就能将所有的点缩成一个点。

#include<stdio.h>



typedef struct edge

        {

               int x;

               edge *n;       

        };

        

bool f[30000];

edge *e[30000],*g[30000];

int q[30000],mark[30000],u[30000],v[30000],num,n,m;

        

void addedge(int x,int y)

{

     edge *p;

     p=new edge;

     p->x=y;

     p->n=e[x];     

     e[x]=p;

     p=new edge;

     p->x=x;

     p->n=g[y];

     g[y]=p;

}

        

void search(int t)

{

     edge *p;

     p=e[t];

     f[t]=true;

     while (p!=NULL)

     {

           if (!f[p->x]) search(p->x);

           p=p->n;

     }     

     q[++num]=t;

}

        

void build(int t,int m)

{

     edge *p;

     p=g[t];

     f[t]=false;

     mark[t]=m;

     while (p!=NULL)

     {

           if (f[p->x]) build(p->x,m);

           p=p->n;

     }

}

        

int main()

{

    int i,x,y;

    while (scanf("%d%d",&n,&m)!=EOF)

    {

          for (i=1; i<=n; i++) e[i]=g[i]=NULL;

          for (i=0; i<m; i++)

          {

              scanf("%d%d",&x,&y);    

              addedge(x,y);

          }      

          for (i=1; i<=n; i++) f[i]=false;

          num=0;

          for (i=1; i<=n; i++) 

              if (!f[i]) search(i);

          num=0;

          for (i=n; i>=1; i--) 

              if (f[q[i]]) 

              {

                 num++;

                 build(q[i],num);             

              }

          for (i=1; i<=num; i++) u[i]=v[i]=0;

          for (i=1; i<=n; i++)

          {

              edge *p;

              p=e[i];

              while (p!=NULL)

              {

                    if (mark[i]!=mark[p->x]) 

                       {

                          u[mark[i]]++;

                          v[mark[p->x]]++;

                       }

                    p=p->n;   

              }    

          }

          int k1=0,k2=0;

          for (i=1; i<=num; i++)

          {

              if (u[i]==0) k1++;

              if (v[i]==0) k2++;

          }

          if (num==1) printf("0\n");

          else if (k1>k2) printf("%d\n",k1);

          else printf("%d\n",k2);

    }

    return 0;

}

  

你可能感兴趣的:(set)