Hdu 2767 把森林变成强连通分量.cpp

题意:

  给出n个点和他们之间的一些关系..

  问加多少条边可以使所有的点变成强连通分量..

 

思路:

  根据题意就可以知道有这个推理:

    原图缩点后的有向无环图..

    出度为0的点和入度为0的点中个数少的那些点向个数多的那些点连线..

    可以使森林变成强连通分量..

 

Tips:

  注意如果缩点后变成一个点了..

  则入度为0和出度为0的点的个数都是1 但是实际上已经是强连通分量..不需要连线了..

  所以答案应该是0

 

Code:

View Code
  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 const int INF = 0x1f1f1f1f;
  6 #define clr(x) memset(x, 0, sizeof(x))
  7 const int MAXN = 20010;
  8 
  9 struct Edge
 10 {
 11     int to;
 12     int next;
 13 }edge[10000010];
 14 int head[MAXN];
 15 int tot;
 16 
 17 void add(int s, int u)
 18 {
 19     edge[tot].to = u;
 20     edge[tot].next = head[s];
 21     head[s] = tot++;
 22 }
 23 
 24 int dfn[MAXN], low[MAXN];
 25 int ins[MAXN], sta[MAXN], col[MAXN];
 26 int ti, top, cnt;
 27 int n;
 28 
 29 void tarjan(int u)
 30 {
 31     int i, k;
 32     dfn[u] = low[u] = ++ti;
 33     ins[u] = 1;
 34     sta[++top] = u;
 35     for(i = head[u]; i != -1; i = edge[i].next) {
 36         k = edge[i].to;
 37         if(dfn[k] == 0) {
 38             tarjan(k);
 39             low[u] = min(low[u], low[k]);
 40         } else if(ins[k]) {
 41             low[u] = min(low[u], dfn[k]);
 42         }
 43     }
 44     if(dfn[u] == low[u]) {
 45         cnt++;
 46         do
 47         {
 48             k = sta[top--];
 49             col[k] = cnt;
 50             ins[k] = 0;
 51         }while(u != k);
 52     }
 53 
 54 }
 55 
 56 void solve_ta()
 57 {
 58     int i, k;
 59     ti = top = cnt = 0;
 60     clr(dfn);
 61     for(i = 1; i <= n; ++i)
 62         if(!dfn[i])
 63             tarjan(i);
 64 }
 65 
 66 int ans;
 67 int in[MAXN], out[MAXN];
 68 void solve()
 69 {
 70     int i, j, k;
 71     ans = 0;
 72     clr(in), clr(out);
 73     solve_ta();
 74 
 75     for(i = 1; i <= n; ++i) {
 76         for(j = head[i]; j != -1; j = edge[j].next) {
 77             k = edge[j].to;
 78             if(col[i] != col[k]) {
 79                 in[col[k]]++;
 80                 out[col[i]]++;
 81             }
 82         }
 83     }
 84 
 85     int tmpa = 0, tmpb = 0;
 86     for(i = 1; i <= cnt; ++i) {
 87         if(in[i] == 0) tmpa++;
 88         if(out[i] == 0) tmpb++;
 89     }
 90 
 91     ans = max(tmpa, tmpb);
 92     if(cnt == 1) ans = 0;
 93 }
 94 
 95 int main()
 96 {
 97     int i, j, k;
 98     int a, b, T, m;
 99     scanf("%d", &T);
100     while(T--)
101     {
102         tot = 0;
103         memset(head, 0xff, sizeof(head));
104 
105         scanf("%d %d", &n, &m);
106         while(m--) {
107             scanf("%d %d", &a, &b);
108             add(a, b);
109         }
110         solve();
111         printf("%d\n", ans);
112     }
113     return 0;
114 }

 

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767

posted @ 2012-10-04 21:42  Griselda.  阅读(215)  评论(0编辑  收藏  举报