poj2186Popular Cows【强连通】【debug两小时】

这个题我调试两个小时,快调哭了都

写一下心得

 

大意:告诉你一群牛  有n头 (n<10^4)

然后告诉你m对羡慕关系  如  a牛羡慕b牛

并且羡慕可以传递  如a羡慕b  b羡慕c  则a羡慕c

现在问有多少只牛是被所有的牛羡慕的

 

分析:我的第一个思路是遍历每个牛 然后从每个牛建立反向边  然后dfs看能否扫到所有的牛  但是这样时间复杂度O(n*(n + e) )  承受不住

后来想到可以像flody传递闭包那样但是同样时间复杂度承受

后来想到这个可以强连通一下子

 

我们首先想这么一个问题
对于一个有向无环图  

满足一个牛被所有牛都羡慕的条件是  :  1  图连通  2  该牛的出度为零(因为他是被所有牛都羡慕的那只  然后如果他再羡慕其他的牛  就会形成环)

对于本题是有环的   用强连通  进行缩点  变成一个有向无环图  再根据那俩条件进行判定即可

 

但是写的时候  首先是我把图中有孤立点这种情况忽略了

然后就是  脑残的break之后……想起来就心痛啊

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 
  6 const int maxn = 50005;
  7 
  8 int n, m;
  9 int tot, cnt;
 10 struct Node {
 11     int to, next;
 12 }e[maxn];
 13 int head[maxn];
 14 
 15 void add(int u, int v) {
 16     e[tot].to = v;
 17     e[tot].next = head[u];
 18     head[u] = tot++;
 19 }
 20 int s[maxn];
 21 int ins[maxn];
 22 int sc;
 23 int ans;
 24 int num[maxn];
 25 
 26 int low[maxn], dfn[maxn];
 27 
 28 void init() {
 29     tot = 1;
 30     memset(head, 0, sizeof(head));
 31     memset(low, 0, sizeof(low));
 32     memset(dfn, 0, sizeof(dfn));
 33     memset(ins, 0, sizeof(ins));
 34     memset(num, 0, sizeof(num));
 35     cnt = 1;
 36     sc = 0;
 37     ans = 0;
 38 }
 39 
 40 void dfs(int u) {
 41     s[sc++] = u;
 42     ins[u] = 1;
 43     for(int i = head[u]; i; i = e[i].next) {
 44         int v = e[i].to;
 45         if(!dfn[v]) {
 46             dfn[v] = low[v] = cnt++;
 47             dfs(v);
 48             low[u] = min(low[u], low[v]);
 49         } else if(ins[v] && !num[v]) {
 50             low[u] = min(low[u], dfn[v]);
 51         }
 52     }
 53     if(low[u] == dfn[u]) {
 54         ans++;
 55         int x;
 56         do {
 57             x = s[--sc];
 58             num[x] = ans;
 59             ins[x] = 0;
 60         } while(x != u);
 61     }
 62 
 63 }
 64 int outed[maxn];
 65 
 66 int main() {
 67     int u, v;
 68     while(EOF != scanf("%d %d",&n, &m) ) {
 69         init();
 70         for(int i = 1; i <= m; i++) {
 71             scanf("%d %d",&u, &v);
 72             add(u, v);
 73         }
 74         for(int i = 1; i <= n; i++) {
 75             if(!dfn[i]) {
 76                 dfn[i] = low[i] = cnt++;
 77                 dfs(i);
 78             }
 79         }
 80     //    for(int i = 1; i <= n; i++) {
 81     //        printf("%d ", num[i]);
 82     //    } puts("");
 83         int ans_num = -1;
 84         memset(outed, 0, sizeof(outed));
 85         for(int i = 1; i <= n; i++) {
 86 //            printf("i = %d\n", i);
 87             if(num[i] == 0) {
 88                 ans_num = 0;
 89                 break;
 90             }
 91             for(int j = head[i]; j ; j = e[j].next) {
 92                 int x = e[j].to;
 93                 if(num[i] != num[x]) {
 94                     outed[num[i]]++;
 95                 }
 96             }
 97         }
 98     //    for(int i = 1; i <= n; i++) {
 99     //        printf("*%d ", outed[i]);
100     //    } puts("");
101     //    printf("ans = %d\n", ans);
102         int flag = 0;
103         if(ans_num != 0) {
104             ans_num = 0;
105             int ax = 0;
106             for(int i = 1; i <= ans; i++) {
107                 if(outed[i] == 0) {
108                     flag++;
109                     if(flag >= 2) {
110                         ans_num = 0;
111                         break;
112                     }
113                     ax = i;
114                 }
115             }
116             if(flag < 2) {
117                 for(int i = 1; i <= n; i++) {
118                     if(num[i] == ax) {
119                         ans_num++;
120                     }
121                 }
122             }
123         }
124         printf("%d\n", ans_num);
125     }
126     return 0;
127 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值