Poj 2186 Popular Cows

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

题意:给定N头牛和M个有序对(A,B)。每头牛都想成为牛群中的popular。(A,B)表示牛A认为牛B是popular。且关系具有传递性,eg:如果A认为B是popular,B认为C是popular,则A认为C是popular。求被其他所有牛认为是popular牛的总数。

题解:是一道典型求强连通分量的题。把图进行强连通分量分解后,至多有一个强连通分量满足题目的条件。得到各个强连通分量拓扑排序后的顺序,唯一可能成为解的只有拓扑排序后的强连通分量。所以只需检查这个强连通分量是否可以从所有顶点到达即可。(求强连通分量用的不是大多数人用的tarjan……而是Kosaraju。Kosaraju与tarjan区别在于Kosaraju需要建立逆图,进行两次DFS。

补充:详细tarjan介绍:http://blog.csdn.net/wsniyufang/article/details/6604458

  1 //
  2 //  main.cpp
  3 //  POJ 2186
  4 //
  5 //  Created by zhang on 14-4-9.
  6 //  Copyright (c) 2014年 apple. All rights reserved.
  7 //
  8 
  9 #include <iostream>
 10 #include <cstring>
 11 #include <cstdio>
 12 #include <cstdlib>
 13 #include <cmath>
 14 #include <string>
 15 #include <vector>
 16 #include <list>
 17 #include <map>
 18 #include <queue>
 19 #include <stack>
 20 #include <bitset>
 21 #include <algorithm>
 22 #include <numeric>
 23 #include <functional>
 24 #include <set>
 25 #include <fstream>
 26 
 27 using namespace std;
 28 
 29 const int maxn=50010;
 30 int A[maxn],B[maxn];
 31 int V;
 32 vector<int> G[maxn];
 33 vector<int> rG[maxn];
 34 vector<int> vs;
 35 bool used [maxn];
 36 int cmp[maxn];//所属强连通分量的拓扑序
 37 int N,M;
 38 void add_edge(int from,int to)
 39 {
 40     G[from].push_back(to);
 41     rG[to].push_back(from);
 42 }
 43 
 44 void dfs(int v)
 45 {
 46     used[v]=true;
 47     for (int i=0; i<G[v].size(); i++) {
 48         if (!used[G[v][i]]) {
 49             dfs(G[v][i]);
 50         }
 51     }
 52     vs.push_back(v);
 53 }
 54 
 55 void rdfs(int v,int k)
 56 {
 57     used[v]=true;
 58     cmp[v]=k;
 59     for (int i=0; i<rG[v].size(); i++) {
 60         if (!used[rG[v][i]]) {
 61             rdfs(rG[v][i], k);
 62         }
 63     }
 64 }
 65 
 66 int scc()
 67 {
 68     memset(used, 0, sizeof(used));
 69     vs.clear();
 70     for (int v=0; v<V; v++) {
 71         if (!used[v]) {
 72             dfs(v);
 73         }
 74     }
 75     memset(used, 0, sizeof(used));
 76     int k=0;
 77     for (int i=vs.size()-1; i>=0; i--) {
 78         if (!used[vs[i]]) {
 79             rdfs(vs[i], k++);
 80         }
 81     }
 82     return k;
 83 }
 84 
 85 //void solve()
 86 //{
 87 
 88 //}
 89 int main()
 90 {
 91     scanf("%d%d",&N,&M);
 92     for (int i=0; i<M; i++) {
 93         scanf("%d%d",&A[i],&B[i]);
 94         add_edge(A[i]-1, B[i]-1);
 95     }
 96     V=N;
 97     int n=scc();
 98     int u=0,num=0;
 99     for (int v=0; v<V; v++) {
100         if (cmp[v]==n-1) {
101             u=v;
102             num++;
103         }
104     }
105     memset(used, 0, sizeof(used));
106     rdfs(u, 0);
107     for (int v=0; v<V; v++) {
108         if (!used[v]) {
109             num=0;
110             break;
111         }
112     }
113     
114     printf("%d
",num);
115 
116     return 0;
117 }
原文地址:https://www.cnblogs.com/der-z/p/3654974.html