受欢迎的牛
题目大意:
有n头牛,牛会喜欢其他牛和自己,而喜欢是可以传递的,求被所有牛喜欢的牛的数量。
思路:
这是一道tarjan缩点的题目。被所有牛都喜欢的牛,一定会在一个强连通分量里。所以我们可以先求出所有强连通分量,缩点后找出度为0的点,如果超过1,则说明没有被所有牛喜欢的牛,如果只有1个,那么受欢迎的牛的数量就是这个点所对应的原来的强连通分量中所含的点的个数。
代码:
1 #include<stack> 2 #include<cstdio> 3 #define N 10010 4 #define M 50010 5 using namespace std; 6 stack<int>p; 7 int next[M],to[M],num,head[N],f[N],dfn[N],low[N],tim,ans2,place[N],n,m,a,b,dis[N],sum,ans; 8 void add(int false_from,int false_to){ 9 next[++num]=head[false_from]; 10 to[num]=false_to; 11 head[false_from]=num; 12 } 13 void tarjan(int x){ 14 p.push(x); 15 dfn[x]=low[x]=++tim; 16 for(int i=head[x];i;i=next[i]){ 17 if(f[to[i]]) 18 continue; 19 if(dfn[to[i]]) 20 low[x]=min(low[x],dfn[to[i]]); 21 else{ 22 tarjan(to[i]); 23 low[x]=min(low[x],low[to[i]]); 24 } 25 } 26 if(dfn[x]==low[x]){ 27 ++ans2; 28 while(p.top()!=x){ 29 f[p.top()]=1; 30 place[p.top()]=ans2; 31 p.pop(); 32 } 33 f[x]=1; 34 place[x]=ans2; 35 p.pop(); 36 } 37 } 38 int main(){ 39 scanf("%d%d",&n,&m); 40 for(int i=1;i<=m;++i){ 41 scanf("%d%d",&a,&b); 42 add(a,b); 43 } 44 for(int i=1;i<=n;++i) 45 if(!dfn[i]) 46 tarjan(i); 47 for(int i=1;i<=n;++i) 48 for(int j=head[i];j;j=next[j]) 49 if(place[i]!=place[to[j]]) 50 dis[place[i]]++; 51 for(int i=1;i<=ans2;++i) 52 if(!dis[i]){ 53 sum++; 54 ans=i; 55 } 56 if(sum>1) 57 printf("0"); 58 else{ 59 sum=0; 60 for(int i=1;i<=n;++i) 61 if(place[i]==ans) 62 sum++; 63 printf("%d",sum); 64 } 65 return 0; 66 }