BZOJ 1051: [HAOI2006]受欢迎的牛(SCC)
1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8172 Solved: 4470
[Submit][Status][Discuss]
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可
能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1
HINT
100%的数据N<=10000,M<=50000
Source
题解:
强连通分量缩点;然后统计每一部分的出度,出度为零;出度为零的即为最受所有人欢迎的牛;(注意:只有有一个这样的“点”,如果有多个,则输出0)
参考代码:
1 #include<bits/stdc++.h> 2 #define N 10050 3 using namespace std; 4 struct EDGE{ 5 int next,to; 6 }edge[N*20]; 7 int head[20*N],dfn[N],low[N]; 8 int du[N],id[N],all[N]; 9 bool insta[N];int cnt,tot,gg,n,m; 10 stack<int>s; 11 inline void add(int x,int y) 12 { 13 cnt++; 14 edge[cnt].to=y; 15 edge[cnt].next=head[x]; 16 head[x]=cnt; 17 } 18 void in(int &read) 19 { 20 int x=0,f=1;char ch; 21 for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); 22 if(ch=='-'){f=-1;ch=getchar();} 23 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 24 read=x*f;//可以处理负数的读入优化 25 } 26 27 void tarjan(int x) 28 { 29 dfn[x]=low[x]=++tot; 30 s.push(x);insta[x]=true; 31 for(int i=head[x];i;i=edge[i].next) 32 { 33 int u=edge[i].to; 34 if(!dfn[u]) 35 { 36 tarjan(u); 37 low[x]=min(low[x],low[u]); 38 } 39 else if(insta[u])low[x]=min(low[x],dfn[u]); 40 } 41 int k; 42 if(low[x]==dfn[x]) 43 { 44 ++gg; 45 do{ 46 k=s.top();s.pop(); 47 insta[k]=false; 48 id[k]=gg;all[gg]++; 49 }while(x!=k); 50 } 51 } 52 int main() 53 { 54 in(n);in(m); 55 int a,b; 56 for(register int i=1;i<=m;i++) 57 { 58 in(a);in(b); 59 add(a,b); 60 } 61 for(register int i=1;i<=n;i++) 62 if(!dfn[i])tarjan(i); 63 for(register int w=1;w<=n;w++) 64 { 65 for(int i=head[w];i;i=edge[i].next) 66 { 67 int u=edge[i].to; 68 if(id[w]!=id[u]) du[id[w]]++; 69 } 70 } 71 int tt=0; 72 for(register int i=1;i<=gg;i++) 73 if(!du[i]) 74 { 75 if(tt){puts("0");return 0;} 76 tt=i; 77 } 78 printf("%d\n",all[tt]); 79 return 0; 80 }