传送门biu~
题目大意: 每头牛都有一个梦想:成为一个群体中最受欢迎的名牛!在一个有N(1<=N<=10,000)头牛的牛群中,给你M(1<=M<=50,000)个二元组(A,B),表示A认为B是受欢迎的。既然受欢迎是可传递的,那么如果A认为B受欢迎,B又认为C受欢迎,则A也会认为C是受欢迎的,哪怕这不是十分明确的规定。你的任务是计算被所有其它的牛都喜欢的牛的个数。
思路:Tarjan缩点,如果图中出度为零的强联通分量数大于一,那么一定不符合题意,输出“0”;如果出度为零的强联通分量等于一,那么答案就是这个强联通分量所包含的点数。
#include<bits/stdc++.h>
using namespace std;
int n,m,ch,ans;
int head[10005],nex[50005],to[50005],tp;
int dfn[10005],low[10005],tim;
int stac[10005],chu[10005],in[10005],siz[10005],num,top;
inline void add(int x,int y){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
}
void dfs(int x){
stac[++top]=x;
dfn[x]=low[x]=++tim;
for(int i=head[x];i;i=nex[i]){
if(!dfn[to[i]]){
dfs(to[i]);
low[x]=min(low[x],low[to[i]]);
}
else if(!in[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}
if(low[x]==dfn[x]){
++num;
while(stac[top]!=x){
in[stac[top--]]=num;
++siz[num];
}
in[stac[top--]]=num;++siz[num];
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;++i)
if(!in[i]) dfs(i);
for(int i=1;i<=n;++i)
for(int j=head[i];j;j=nex[j])
if(in[i]!=in[to[j]]) ++chu[in[i]];
for(int i=1;i<=num;++i){
if(chu[i]) continue;
if(ch++) {printf("0");return 0;}
ans=siz[i];
}
printf("%d",ans);
return 0;
}