题目链接:http://poj.org/problem?id=2186
题目大意:
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
解题思路:
假设有两头牛A和B都被其他所有牛认为是红人,那么显然,A被B认为是红人,B也被A认为是红人,即存在一个包含A、B两个顶点的圈,或者说,A、B同属于一个强联通分量。所以
如果有一头牛被其他所有牛认为是红人,那么其所属的强联通分量内的所有牛都被其他所有牛认为是红人。我们把图进行强联通分量分解后,至多有一个强联通分量满足题目的条件。
做法: 先用tarjan求出每个强连通分量,再缩点,统计每个点的出度,如果有且只有1个出度为0的点,就输出这个点包含的节点数,否则输出0。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 using namespace std; 8 const int N=1e4+5; 9 10 int cnt,num; 11 int dfn[N],low[N],fa[N],sze[N],outdeg[N]; 12 stack<int>sk; 13 vector<int>v[N]; 14 15 void tarjan(int u){ 16 dfn[u]=low[u]=++cnt; 17 sk.push(u); 18 for(int i=0;i<v[u].size();i++){ 19 int t=v[u][i]; 20 if(!dfn[t]){ //点t未被访问 21 tarjan(t); 22 low[u]=min(low[u],low[t]); 23 } 24 else if(!fa[t]) low[u]=min(low[u],dfn[t]); //点t已被访问,且t还在栈中 25 } 26 if(low[u]==dfn[u]){ 27 num++; 28 while(1){ 29 int t=sk.top(); 30 sk.pop(); 31 fa[t]=num; //缩点操作,将这些点都归为点num 32 sze[num]++; 33 if(t==u) break; 34 } 35 } 36 } 37 38 int main(){ 39 int n,m; 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=m;i++){ 42 int a,b; 43 scanf("%d%d",&a,&b); 44 v[a].push_back(b); 45 } 46 for(int i=1;i<=n;i++){ 47 if(!dfn[i]) tarjan(i); 48 } 49 for(int i=1;i<=n;i++){ 50 for(int j=0;j<v[i].size();j++){ 51 int t=v[i][j]; 52 if(fa[t]!=fa[i]) outdeg[fa[i]]++; 53 } 54 } 55 //缩点后,出度为0的点只能有一个,否则不符合条件输出0 56 int ans=0; 57 for(int i=1;i<=num;i++){ 58 if(!outdeg[i]){ 59 if(ans>0){ 60 puts("0"); 61 return 0; 62 } 63 ans=sze[i]; 64 } 65 } 66 printf("%d\n",ans); 67 return 0; 68 }