nkoj 2243
Description
每头奶牛都梦想着成为牛群中的明星,成为奶牛们的偶像。约翰的牛群共有N (1 <= N <= 10,000)头奶牛,现在告诉你M (1 <= M <= 50,000) 条奶牛间的关系,形如(A,B),意味着奶牛A认为奶牛B是它心目中的偶像,这种偶像关系可以传递,也就是说如果A认为B是它的偶像,B认为C是它的偶像,那么A也会认为C是它的偶像。
你的任务是找出被所有的奶牛都当做偶像的奶牛的数目。
Input
第一行,两个整数N和M
接下来M行,每行两个整数A和B,表明A认为B是它的偶像。
Output
一个整数,表示所求结果
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
分析:
首先,膜拜和被膜拜的关系可以传递,所以这种崇拜关系实际上是以强连通分量为单位的。
用Kosaraju算出来的一个一个的强连通分量都是满足拓扑顺序的,也就是说只有最后找到的那个强连通分量才有可能是被所有奶牛 膜拜的集合。但是如果存在出度为0的强连通分量:那就只能是最后一个,否则属于无解的情况。如果有解,答案就是最后一个强连通分量中有几个点。代码如下:#include<cstdio> #include<cstring> using namespace std; const int maxn=10005,maxm=50005; bool out[maxn],mark[maxn]; int vis[maxn],id[maxn]; int next[maxm][2],last[maxn][2],to[maxm][2]; //第二维是0表示正图,1表示反图。 int n,cnt=0,scc=0,tot,m; void dfs1(int x){ mark[x]=true; for(int i=last[x][0];i;i=next[i][0]) if(!mark[to[i][0]])dfs1(to[i][0]); vis[++cnt]=x; } void dfs2(int x){ mark[x]=true; id[x]=scc; for(int i=last[x][1];i;i=next[i][1]) if(!mark[to[i][1]])dfs2(to[i][1]); } void kosaraju(){ int i,j,k,temp; for(i=1;i<=n;i++) if(!mark[i])dfs1(i); memset(mark,0,sizeof(mark)); //注意一定要清零 for(i=cnt;i>0;i--) if(!mark[vis[i]]){ scc++;dfs2(vis[i]); } for(i=1;i<=n;i++) for(j=last[i][0];j;j=next[j][0]) if(id[i]!=id[to[j][0]])out[id[i]]=true; //检查每一个强连通分量是否有出度 k=scc; for(i=1;i<=scc;i++)if(!out[i])tot++,k=i;//找出没有出度的分量 if(tot>1||k!=scc){ printf("0\n");return ; } int ans=0; for(i=1;i<=n;i++)if(id[i]==scc)ans++; //找出最后一个强连通分量中有几个点。 printf("%d\n",ans); } int main(){ int i,j,x,y; scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ //存图 scanf("%d%d",&x,&y); to[i][0]=y; to[i][1]=x; next[i][1]=last[y][1]; next[i][0]=last[x][0]; last[y][1]=i; last[x][0]=i; } kosaraju(); }