zoukankan      html  css  js  c++  java
  • 洛谷 P2341 【受欢迎的牛】


    思路:因为奶牛的爱慕关系具有传递性,所以每个环(强连通分量)里的奶牛是互相喜欢的。那么我们可以用到Tarjan算法把每个强连通分量找出,并缩点,把每个强连通分量都缩成一个点(当前缩点里的奶牛都是互相喜欢的)。这样一来,这个图就变成了一个DAG(有向无环图)。然后我们只需要统计每个缩点的出度就好了,如果一个点有出度&&我们知道这个图是一个DAG,所以这个强连通分量(这个缩点)里的奶牛就不可能被这个缩点所连出去的缩点里的奶牛所喜欢(这是无环图——DAG)。综上所述,我们只需要统计一下有多少个没有出度的强连通分量就好了,但有多个没有出度的强连通分量也不行,因为这样就会有两多群群奶牛不喜欢别的奶牛,使得奶牛们无法收到其他奶牛(这多群奶牛)的喜欢,这样就不行了 。

    画一张图形象一下:

    code :

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 using namespace std;
     4 const int MAX = 5e4 + 1;
     5 stack < int > pru;
     6 int n, m, low[MAX], dfn[MAX], head[MAX], vis[MAX], col[MAX], sum[MAX], color, num, z, out[MAX], ans, cnt;
     7 struct node
     8 {
     9     int next, to;
    10 }stu[MAX];
    11 inline void add(int x, int y)
    12 {
    13     stu[++num].next = head[x];;
    14     stu[num].to = y;
    15     head[x] = num;
    16     return;    
    17 }
    18 inline void tarjan(int u)//Tarjan算法模板,这里用于缩点 
    19 {
    20     low[u] = dfn[u] = ++z;
    21     vis[u] = 1;
    22     pru.push(u);
    23     for(register int i = head[u]; i; i = stu[i].next)
    24     {
    25         int k = stu[i].to;
    26         if(!vis[k])
    27         {
    28             tarjan(k);
    29             low[u] = min(low[u], low[k]);
    30         }
    31         else if(!col[k])
    32         {
    33             low[u] = min(low[u], dfn[k]);
    34         }
    35     }
    36     if(low[u] == dfn[u])
    37     {
    38         col[u] = ++color;
    39         ++sum[color];//当前强连通分量里的奶牛的个数++ 
    40         while(pru.top() != u)
    41         {
    42             col[pru.top()] = color;
    43             ++sum[color];//当前强连通分量里的奶牛的个数++
    44             pru.pop();
    45         }
    46         pru.pop();
    47     }
    48     return;
    49 }
    50 signed main()
    51 {
    52     scanf("%d %d", &n, &m);
    53     for(register int i = 1, x, y; i <= m; ++i)
    54     {
    55         scanf("%d %d", &x, &y);
    56         add(y, x);//建反向边,把统计出度变为统计入度,更加方便一些 
    57     }
    58     for(register int i = 1; i <= n; ++i)
    59     {
    60         if(!vis[i])
    61         {
    62             tarjan(i);
    63         }
    64     }
    65     for(register int u = 1; u <= n; ++u)//循环每个结点的出度(这里是入度,因为建的是反向边) 
    66     {
    67         for(register int i = head[u]; i; i = stu[i].next)
    68         {
    69             int k = stu[i].to;//因为建的是反向边,所以i其实是k的出度 
    70             if(col[k] != col[u])//颜色不相同就代表不在一个强连通分量里 
    71             {
    72                 ++out[col[k]];//所以k的颜色(及包含k的那个强连通分量)就不能选了(这里标记为出度++),至于为什么思路里有讲 
    73             }
    74         }
    75     }
    76     for(register int i = 1; i <= color; ++i)//枚举每种颜色(每个强连通分量) 
    77     {
    78         if(!out[i])//要是没有出度(及当前强连通分量中没有奶牛喜欢别的奶牛) 
    79         {
    80             ++cnt;//记录有几个强连通分量的缩点没有出度 
    81             ans = sum[i];//注意,这里是sum[i],因为i点只是当前强连通分量的缩点,真正被所有奶牛都喜欢的奶牛个数其实是这个强连通分量的大小(及当前强连通分量中奶牛的个数) 
    82         }
    83     }
    84     if(cnt == 1)//必须只有一个强连通分量没有出度,如果有多个也不行,因为这样那两个强连通分量里的奶牛都是不互相喜欢的 
    85     {
    86         printf("%d", ans);
    87     }
    88     else
    89     {
    90         printf("0");//没有奶牛被所有奶牛喜欢 
    91     }
    92     return 0;
    93 }
  • 相关阅读:
    ionic入门教程第十二课-通用模块的分离$ionicModal
    ionic入门教程第十一课-简要说明ion-list、ion-item完成列表页ion-infinite-scroll上拉加载ion-refresher下拉刷新
    ionic入门教程第十课-接着说说ion-slide-box和它的注意事项、slide-tabs
    ionic入门教程第九课-开始动手做项目吧!ion-nav-bar、ion-nav-buttons、ion-tabs
    ionic入门教程第八课-(加更)从无到有说Ionic、画图说明MVC-U-S
    ionic入门教程第七课-简要说明几种界面之间的参数传递及优缺点
    ionic入门教程第六课-从服务器请求数据的几种方式$http.get()、jsonp()分别和callback、$q的组合
    Java 8 API Stream让List操作更便捷
    程序员常用linux命令ls,ll,cd,more,tail,rm,mv,find,vi,mdir,touch,ps,kill详解
    java数组插入排序代码详解
  • 原文地址:https://www.cnblogs.com/qqq1112/p/11195117.html
Copyright © 2011-2022 走看看