题意:
给出n头牛,m个关系,关系x,y表示牛x喜欢牛y,如果x喜欢y,y喜欢z,那么x也喜欢z。
是否存在一些牛,其他所有牛都喜欢他。
明显,如果是一个大的联通分量,那么他们相互喜欢,如果有几个联通分量,那么如果有两个或两个以上的联通分量没有指向其他联通分量,那么这样的牛是不存在的,如图:
所以我们出了计算联通分量,还要存放,某个联通分量有多少个牛组成,以及这个联通分量有没有出度,如果这样的牛存在,那么它所在的联通分量必然出度为0,并且只有1个出度为0的联通分量。
//POJ_2186_Popular Cows
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=1e5+6;
int sum[maxn],col[maxn],outdeg[maxn],sta[maxn];
int n,m,tim,cnt,Count,top,head[maxn],dfn[maxn],vis[maxn],low[maxn];struct node
{int to,nxt;
};
node edge[500005];
void init(){memset(head,-1,sizeof(head));tim=cnt=top=Count=0;for(int i=0;i<=n;i++)sum[i]=col[i]=outdeg[i]=sta[i]=dfn[i]=vis[i]=low[i]=0;
}
void add(int u,int v){edge[cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt++;
}
void tarjian(int u){vis[u]=1;dfn[u]=low[u]=tim++;sta[++top]=u;for(int i=head[u];i!=-1;i=edge[i].nxt){int v=edge[i].to;if(vis[v]==0) tarjian(v);if(vis[v]==1) low[u]=min(low[u],low[v]);}if(low[u]==dfn[u]){Count++;do{col[sta[top]]=Count;//属于第几个联通分量sum[Count]++;//该联通分量有几个节点vis[sta[top]]=-1;}while(sta[top--]!=u);//出栈}
}
int main(){while (scanf("%d%d",&n,&m)!=EOF){int x,y;init();for(int i=0;i<m;i++){scanf("%d%d",&x,&y);add(x,y);}for(int i=1;i<=n;i++)if(!vis[i]) tarjian(i);for(int i=1;i<=n;i++){for(int j=head[i];j!=-1;j=edge[j].nxt){int v=edge[j].to;if(col[i]!=col[v]) //i与它指向的点不是同一个联通分量outdeg[col[i]]++; //i所在的联通分量出度++}}int ans = 0,flag=0;//利用flag 来标记是第几次出度为0;for (int i = 1; i <=Count; i++){if(flag && outdeg[i]==0){//如果falg =1 后,说明已经有了一个出度为0的,如果再有,ans=0;ans=0;break;}if(!flag && outdeg[i]==0){//开始 flag =0 此时如果有出度为0的,那么ans有了ans=sum[i];flag=1;}}printf("%d\n",ans);}return 0;
}