【强连通分量】奶牛偶像 usaco 2003

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();
}


你可能感兴趣的:(【强连通分量】奶牛偶像 usaco 2003)