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

    http://poj.org/problem?id=2186

    Popular Cows
    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 20191   Accepted: 8193

    Description

    Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is  popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow. 

    Input

    * Line 1: Two space-separated integers, N and M 
    * Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular. 

    Output

    * Line 1: A single integer that is the number of cows who are considered popular by every other cow. 

    Sample Input

    3 3
    1 2
    2 1
    2 3
    

    Sample Output

    1
    

    Hint

    Cow 3 is the only cow of high popularity. 
     
    【题解】:
        
    有N(N<=10000)头牛,每头牛都想成为most poluler的牛,给出M(M<=50000)个关系,如(1,2)代表1欢迎2,关系可以传递,但是不可以相互,即1欢迎2不代表2欢迎1,但是如果2也欢迎3那么1也欢迎3.
    给出N,M和M个欢迎关系,求被所有牛都欢迎的牛的数量。
    用强联通分量做,求连通分量我用的是tarjan算法。
    首先求出联通分量的个数,然后依次求各个联通分量的出度,如果仅有一个连通分量出度为0则这个联通分量内的点的个数就是答案;如果有多于一个的联通分量的出度为0,则说明此有向图肯定不连通。因此直接输出0。
     
    缩点的意思就是说把求得的强连通分量的点集看成一个点
     
     
    【code】:
      1 /**
      2 Judge Status:Accepted      Memory:2404K
      3 Time:532MS      Language:G++
      4 Code Length:1971B   Author:cj
      5 */
      6 #include<iostream>
      7 #include<stdio.h>
      8 #include<string.h>
      9 #include<stack>
     10 #include<vector>
     11 #include<algorithm>
     12 
     13 #define N 10010
     14 using namespace std;
     15 
     16 vector<int> G[N];
     17 stack<int> stk;
     18 int pre[N],lowlink[N],sccno[N],scc_cnt,dfn_clock,out[N],counter[N];
     19 
     20 
     21 void DFN(int u)  //tarjan算法
     22 {
     23     lowlink[u] = pre[u] = ++dfn_clock;
     24     stk.push(u);
     25     int i;
     26     for(i=0;i<G[u].size();i++)
     27     {
     28         int v = G[u][i];
     29         if(!pre[v])
     30         {
     31             DFN(v);
     32             lowlink[u] = min(lowlink[u],lowlink[v]);
     33         }
     34         else if(!sccno[v])
     35         {
     36             lowlink[u] = min(lowlink[u],pre[v]);
     37         }
     38     }
     39     if(lowlink[u]==pre[u])
     40     {
     41         scc_cnt++;  //强连通图的个数标记
     42         while(1)
     43         {
     44             int x = stk.top();
     45             stk.pop();
     46             sccno[x] = scc_cnt;
     47             if(x==u)    break;
     48         }
     49     }
     50 }
     51 
     52 void findscc(int n)
     53 {
     54     int i;
     55     scc_cnt = dfn_clock = 0;
     56     memset(pre,0,sizeof(pre));
     57     memset(lowlink,0,sizeof(lowlink));
     58     memset(sccno,0,sizeof(sccno));
     59     for(i=1;i<=n;i++)
     60         if(!pre[i])
     61             DFN(i);
     62 }
     63 
     64 int main()
     65 {
     66     int n,m;
     67     scanf("%d%d",&n,&m);
     68     int i;
     69     for(i=0;i<m;i++)
     70     {
     71         int a,b;
     72         scanf("%d%d",&a,&b);
     73         G[a].push_back(b);  // 得到图
     74     }
     75     findscc(n);  //查找强连通图
     76     int j;
     77     memset(out,0,sizeof(out));
     78     memset(counter,0,sizeof(counter));
     79 
     80     for(i=1;i<=n;i++)  //遍历一边图,查找统计个点缩点后的出度
     81     {
     82        // cout<<sccno[i]<<" ";
     83         for(j=0;j<G[i].size();j++)
     84         {
     85             int v = G[i][j];
     86             if(sccno[i]!=sccno[v])
     87             {
     88                 out[sccno[i]]++;  //出度
     89             }
     90         }
     91     }
     92 
     93     for(i=1;i<=n;i++)
     94     {
     95         counter[sccno[i]]++;  //统计各个强连通分量中的节点个数
     96     }
     97 
     98     int cnt =0,ans = 0;
     99     for(i=1;i<=scc_cnt;i++)
    100     {
    101         if(!out[i])  //出度为0的强连通分量
    102         {
    103             cnt++;
    104             ans = counter[i];  //答案即为其中的点集数
    105         }
    106     }
    107 
    108     if(cnt==1)  printf("%d
    ",ans);
    109     else puts("0");
    110 
    111     return 0;
    112 }
  • 相关阅读:
    vim使用
    linux下编译openjdk8
    《鸟哥的Linux私房菜》学习笔记(9)——条件判断
    《鸟哥的Linux私房菜》学习笔记(8)——bash脚本编程之变量
    《鸟哥的Linux私房菜》学习笔记(7)——grep及正则表达式
    《鸟哥的Linux私房菜》学习笔记(6)——管道及IO重定向
    《鸟哥的Linux私房菜》学习笔记(5)——权限管理
    《鸟哥的Linux私房菜》学习笔记(4)——用户和组
    《鸟哥的Linux私房菜》学习笔记(0)——磁盘与文件系统管理
    Intellij Idea 创建JavaWeb项目
  • 原文地址:https://www.cnblogs.com/crazyapple/p/3250312.html
Copyright © 2011-2022 走看看