1 /*************************************************
  2      Proving Equivalences(hdu 2767)
  3      强连通入门题
  4      给个有向图,求至少加多少条边使得图是所有点都是强连通的
  5      由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大
  6      于1。先求所有所有强连通分量,把每个强连通分量看成一个点
  7      在找每个点的出度和入度,最后还差的出度和入度的最大值就是
  8      答案。
  9 
 10 *************************************************/
 11 
 12 
 13 #include<cstdio>
 14 #include<iostream>
 15 #include<cstring>
 16 #include<algorithm>
 17 #include<stack>
 18 #include<vector>
 19 using namespace std;
 20 
 21 const int mx=20005;
 22 stack<int>s;
 23 vector<int>g[mx];
 24 int dfn[mx],low[mx];
 25 int sccno[mx],vs[mx];
 26 int cut_dfs,cut_scc;
 27 int in[mx],out[mx];
 28 
 29 void Init(int n)
 30 {
 31     cut_dfs=cut_scc=0;
 32     memset(sccno,0,sizeof(sccno));
 33     memset(dfn,0,sizeof(dfn));
 34     memset(low,0,sizeof(low));
 35     memset(vs,0,sizeof(vs));
 36     for (int i=1;i<=n;i++) g[i].clear();
 37     while (!s.empty()) s.pop();
 38 }
 39 
 40 void dfs(int u)
 41 {
 42 
 43     s.push(u);
 44     low[u]=dfn[u]=++cut_dfs;
 45     vs[u]=1;
 46     for (int i=0;i<g[u].size();i++)
 47     {
 48         int v=g[u][i];
 49         if (!vs[v])
 50         {
 51             dfs(v);
 52             low[u]=min(low[u],low[v]);
 53         }
 54         else if (!sccno[v]) low[u]=min(low[u],dfn[v]);///一定要加if (!sccno[v])
 55     }
 56 
 57     if (low[u]==dfn[u])
 58     {
 59         cut_scc++;
 60         while (1)
 61         {
 62             int v=s.top();
 63             s.pop();
 64             sccno[v]=cut_scc;
 65             if (v==u) break;
 66         }
 67     }
 68 }
 69 
 70 int main()
 71 {
 72     int t,n,m;
 73     scanf("%d",&t);
 74     while (t--)
 75     {
 76         scanf("%d%d",&n,&m);
 77         Init(n);
 78         int a,b;
 79         while (m--)
 80         {
 81             scanf("%d%d",&a,&b);
 82             g[a].push_back(b);
 83         }
 84         for (int i=1;i<=n;i++)
 85         {
 86             if (!dfn[i]) dfs(i);
 87         }
 88 
 89         if (cut_scc==1)
 90         {
 91             printf("0\n");
 92             continue;
 93         }
 94         for (int i=1;i<=cut_scc;i++) in[i]=out[i]=1;
 95         for (int i=1;i<=n;i++)
 96         {
 97             for (int j=0;j<g[i].size();j++)
 98             {
 99                 int v=g[i][j];
100                 if (sccno[i]!=sccno[v]) out[sccno[i]]=in[sccno[v]]=0;
101             }
102         }
103         a=b=0;
104         for (int i=1;i<=cut_scc;i++)
105         {
106             if (out[i]) a++;
107             if (in[i]) b++;
108         }
109         printf("%d\n",max(a,b));
110     }
111 }

 

posted on 2016-04-24 21:10  pb2016  阅读(187)  评论(0编辑  收藏  举报