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 }