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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章