poj 2186 (强连通缩点)

题意:有N只奶牛,奶牛有自己认为最受欢迎的奶牛。奶牛们的这种“认为”是单向可传递的,当A认为B最受欢迎(B不一定认为A最受欢迎),且B认为C最受欢迎时,A一定也认为C最受欢迎现在给出M对这样的“认为...”的关系,问有多少只奶牛被除其本身以外的所有奶牛关注。

思路:既然有单向传递关系,那么关系图可能就形成了环,一个环内的奶牛互相认为。如果把这些环用一个点代替的话,建反图,就成了一个有向无环图了,直接遍历求出入度为0的点有多少个子节点就可以了。






 

#include<stdio.h>

#include<string.h>

#include<stack>

using namespace std;

const int N=10010;

int low[N],dfs[N],ans,idx,cont[N],head[N],num,indep[N],belong[N],sum;

bool ins[N];

stack<int>Q;

struct edge

{

	int st,ed,next;

}e[N*10];

void addedge(int x,int y)

{

	e[num].st=x;e[num].ed=y;e[num].next=head[x];head[x]=num++;

}

void Tarjan(int u)//缩点

{

	int i,v;

	Q.push(u);

	ins[u]=1;

	low[u]=dfs[u]=idx++;

	for(i=head[u];i!=-1;i=e[i].next)

	{

		v=e[i].ed;

		if(dfs[v]==-1)

		{

			Tarjan(v);

			low[u]=low[u]>low[v]?low[v]:low[u];

		}

		else if(ins[v]==1)

			low[u]=low[u]>dfs[v]?dfs[v]:low[u];

	}

	if(dfs[u]==low[u])

	{

		do

		{

			v=Q.top();

			Q.pop();

			ins[v]=0;

			belong[v]=ans;

			cont[ans]++;

		}while(v!=u);

		ans++;

	}

}

int Dfs(int u)

{

	int i,v,temp=0;

	for(i=head[u];i!=-1;i=e[i].next)

	{

		v=e[i].ed;

		temp+=Dfs(v);

	}

	return temp+cont[u];//子节点+自己环内的所有点

}

int main()

{

	int i,n,m,x,y;

	while(scanf("%d%d",&n,&m)!=-1)

	{

		memset(head,-1,sizeof(head));

		num=0;ans=idx=0;

		for(i=0;i<m;i++)

		{

			scanf("%d%d",&x,&y);

			addedge(x,y);

		}

		memset(cont,0,sizeof(cont));

		memset(ins,0,sizeof(ins));

		memset(dfs,-1,sizeof(dfs));

		for(i=1;i<=n;i++)

		{

			if(dfs[i]==-1)

				Tarjan(i);

		}

		memset(head,-1,sizeof(head));

		memset(indep,0,sizeof(indep));

		num=0;

		for(i=0;i<m;i++)

		{

			x=belong[e[i].st];

			y=belong[e[i].ed];

			if(x==y)continue;

			addedge(y,x);//建反图

			indep[x]++;

		}

		sum=0;

		for(i=0;i<ans;i++)

		{

			if(indep[i]==0)

				if(Dfs(i)==n)

					sum+=cont[i];

		}

		printf("%d\n",sum);

	}

	return 0;

}


 

 

你可能感兴趣的:(poj)