zoukankan      html  css  js  c++  java
  • POJ 2186 Popular Cows(强连通分量缩点)

    题目链接:http://poj.org/problem?id=2186

    题目意思大概是:给定N(N<=10000)个点和M(M<=50000)条有向边,求有多少个“受欢迎的点”。所谓的“受欢迎的点”当且仅当任何一个点出发都能到达它。

    原来的图是无序且可能有环,用tarjan缩点,变成一个DAG。受欢迎点的出度一定为0,所以缩点后求有多少个连通分量的出度是0,要是大于1则没有受欢迎的点,等于1的话求出这个出度为0的连通分量有多少个点。

    强联通分量tarjan算法里邻接表用vector一般好理解,但是速度不及链式前向星,链式前向星学习链接:http://blog.csdn.net/acdreamers/article/details/16902023

    AC代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 const int MAXN = 1e4 + 5;
     7 struct data {
     8     int next , to;
     9 }edge[MAXN * 5];
    10 int head[MAXN] , low[MAXN] , dfn[MAXN] , block[MAXN] , st[MAXN];
    11 int top , ord , sccnum;
    12 bool instack[MAXN] , out[MAXN];
    13 
    14 void init(int n) {
    15     for(int i = 1 ; i <= n ; i++) {
    16         low[i] = dfn[i] = 0;
    17         head[i] = -1;
    18         instack[i] = false;
    19     }
    20     top = ord = sccnum = 0;
    21 }
    22 
    23 void tarjan(int u) {
    24     low[u] = dfn[u] = ++ord;
    25     st[++top] = u;
    26     instack[u] = true;
    27     for(int i = head[u] ; ~i ; i = edge[i].next) { //链式前向星
    28         int v = edge[i].to;
    29         if(!dfn[v]) {
    30             tarjan(v);
    31             low[u] = min(low[u] , low[v]);
    32         }
    33         else if(instack[v]) {
    34             low[u] = min(low[u] , dfn[v]);
    35         }
    36     }
    37     if(low[u] == dfn[u]) {
    38         int v;
    39         sccnum++;
    40         do {
    41             v = st[top--];
    42             instack[v] = false;
    43             block[v] = sccnum;
    44         }while(u != v);
    45     }
    46 }
    47 
    48 int main()
    49 {
    50     int n , m , u , v;
    51     while(~scanf("%d %d" , &n , &m)) {
    52         init(n);
    53         for(int i = 0 ; i < m ; i++) {
    54             scanf("%d %d" , &u , &v);
    55             edge[i].to = v;     //链式前向星
    56             edge[i].next = head[u];
    57             head[u] = i;
    58         }
    59         for(int i = 1 ; i <= n ; i++) {
    60             if(!dfn[i])
    61                 tarjan(i);
    62         }
    63         memset(out , false , sizeof(out)); //缩点是否有入度
    64         for(int u = 1 ; u <= n ; u++) {
    65             for(int i = head[u] ; ~i ; i = edge[i].next) { //链式前向星
    66                 int v = edge[i].to;
    67                 if(block[v] != block[u])  //不是同一个连通分量
    68                     out[block[u]] = true;
    69             }
    70         }
    71         int res = 0 , op = -1;
    72         for(int i = 1 ; i <= sccnum ; i++) {
    73             if(!out[i]) {  //出度为0的点
    74                 res++;
    75                 op = i;
    76             }
    77         }
    78         if(res > 1) {
    79             printf("0
    ");
    80         }
    81         else {
    82             res = 0;
    83             for(int i = 1 ; i <= n ; i++) {
    84                 if(block[i] == op)
    85                     res++;
    86             }
    87             printf("%d
    " , res);
    88         }
    89     }
    90 }
  • 相关阅读:
    2020-2021-1 20201216 《信息安全专业导论》第十周学习总结
    2020-2021-1 20201216 《信息安全专业导论》第9周学习总结
    熟悉编程语言
    2020-2021-1 20201216 《信息安全专业导论》第八周学习总结
    如何学好编程
    2020-2021第一学期20202428《计算机科学概论》第二周自习总结
    “七剑下天山”学习小组第一周学习中遇到的问题及解决
    2020-2021第一学期20202407《计算机科学概论》第一次学习总结
    开启我的测试之路
    大数据测试
  • 原文地址:https://www.cnblogs.com/Recoder/p/5255728.html
Copyright © 2011-2022 走看看