hdu 2767 Proving Equivalences(强连通 缩点 以及判断入度 出度)

题意

    补最少的边成强连通图。

     缩点后,max{ 入度为0点数, 出度为零点数}即为所求的值

  (vector,belong,DFN,LOW)                              

View Code
  1 #include<stdio.h>
  2 #include<vector>
  3 #include<string.h>
  4 using namespace std;
  5 vector <int> Q[20005],R[20005];
  6 int x,y,Num;
  7 bool instack[20005];  //标记在栈里的元素
  8 int stack[20005];    //存储当前在栈里的元素
  9 int low[20005],DFN[20005]; //DFN表示该数被访问的顺序;low值更新为一个强连通里面最开始访问的那个数的顺序(所以一开始low值与DFN的值相同);
 10 int belong[20005];        //将处于同一个强连通的所有分量赋相同的值存于其中
 11 int in[20005],out[20005]; //缩点之后 判断是否存在入度或者出度
 12 
 13 void Init_tarjan(int n)
 14 {
 15     x=0;y=0;Num=0;
 16     for(int i=1;i<=n;i++)
 17     {
 18         Q[i].clear();
 19         R[i].clear();
 20     }
 21     memset(low,0,sizeof(low));
 22     memset(DFN,0,sizeof(DFN));
 23     memset(in,0,sizeof(in));
 24     memset(out,0,sizeof(out));
 25     memset(belong,0,sizeof(belong));
 26     memset(instack,false,sizeof(instack));
 27 }
 28 
 29 void tarjan(int i)
 30 {
 31     DFN[i]=low[i]=++y;   //为节点i设定次序编号和Low初值   //如果初始化为0;不能写成y++;
 32     stack[++x]=i;      //压入栈中
 33     instack[i]=true;  //标记在栈中的元素
 34     for(int j=0;j<Q[i].size();j++)
 35     {
 36         int k=Q[i][j];
 37         if(!DFN[k])
 38         {
 39             tarjan(k); //未被访问过,调用此函数
 40             low[i]=min(low[i],low[k]); //更新low值
 41         }
 42         else if(instack[k])
 43         {
 44             low[i]=min(low[i],DFN[k]);//访问到已在栈中的元素,比较访问的顺序,去较小的一个。
 45         }
 46     }
 47     if(DFN[i]==low[i])
 48     {
 49         Num++;  //记录强连通分量个数
 50         int j;
 51         do
 52         {
 53             j=stack[x--];
 54             belong[j]=Num;  //将处于同一个强连通的所有分量赋相同的值
 55             instack[j]=false;
 56         }while(j!=i);    //到删除DFN值和low值相同的点截止
 57     }
 58 }//求强连通分量个数
 59 
 60 void Creat_New_Grap(int n)
 61 {
 62     for(int i=1;i<=n;i++)
 63     {
 64         for(int j=0;j<Q[i].size();j++)
 65         {
 66             int k=Q[i][j];
 67             if(belong[k]!=belong[i])  //有指向其他强连通分量的边
 68                R[belong[i]].push_back(belong[k]);
 69         }
 70     }
 71     for(int i=1;i<=Num;i++)
 72     {
 73         for(int j=0;j<R[i].size();j++)
 74         {
 75             int k=R[i][j];
 76             in[k]=1;     //第k个强连通分量有入度
 77             out[i]=1;   //第i个强连通分量有出度
 78         }
 79     }
 80 }//缩点建新图
 81 
 82 int main()
 83 {
 84    int N;
 85    scanf("%d",&N);
 86    while(N--)
 87    {
 88        int i,j,n,m,a,b;
 89        scanf("%d %d",&n,&m);
 90     Init_tarjan( n);
 91        for(i=1;i<=m;i++)
 92        {
 93            scanf("%d %d",&a,&b);
 94            Q[a].push_back(b);
 95        }
 96        for(i=1;i<=n;i++)
 97            if(!DFN[i])
 98                  tarjan(i);
 99         if(Num==1) printf("0\n");
100         else
101         {
102     Creat_New_Grap(n);
103             int X=0,Y=0;
104             for(i=1;i<=Num;i++)
105             {
106                 if(in[i]==0) X++;
107                 if(out[i]==0)Y++;
108             }
109             if(X>Y)  printf("%d\n",X);
110             else  printf("%d\n",Y);
111         }
112 
113    }
114 }

 

posted @ 2013-04-29 21:19  lysr__tlp  阅读(253)  评论(0)    收藏  举报