Popular Cows-POJ2186Tarjan

Time Limit: 2000MS   Memory Limit: 65536K
     

Descriptionnode

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Inputide

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Outputthis

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Inputspa

3 3
1 2
2 1
2 3

Sample Outputcode

1

Hintorm

Cow 3 is the only cow of high popularity.

Sourceblog

USACO 2003 Fall

題意:每個奶牛都想成爲牧羣中最受仰慕的奶牛,在牧羣中有n頭奶牛,給定m對關係(A,B),表示A奶牛仰慕B奶牛。計算牧羣中被其餘奶牛仰慕的奶牛的數目。

思路:將n頭奶牛的m個關係將會構建一個有向圖,在圖中強連通份量中的任意奶牛必定是被份量中的其餘奶牛仰慕。因此問題就轉化爲在圖中將強連通份量進行縮點,在造成的新圖中,若是一個強連通份量集合的出度爲零,說明這個集合被其餘集合仰慕,而不仰慕其餘的集合,因此若是在新圖中集合出度爲零的數目不大於1,則爲出度爲零集合中奶牛的數目,若是大於1,則出度爲零集合之間沒有仰慕關係的,因此結果爲0.

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

const int Max = 10100;

typedef struct node
{
	int v;

	int next;

}Line;

vector<int>G[Max];

Line Li[Max*5];

int Head[Max],top;

int dfn[Max],low[Max],pre[Max];

int num[Max],Num,Du[Max];

int dep;

bool vis[Max];

int ans;

stack<int>S;

void AddEdge(int u,int v)
{
	Li[top].v=v ; Li[top].next=Head[u];

	Head[u]=top++;
}

void Tarjan(int u)// Tarjan求強連通份量
{
	dfn[u]=low[u]=dep++;

	S.push(u);
	
	for(int i=Head[u];i!=-1;i=Li[i].next)
	{
		if(dfn[Li[i].v]==-1)
		{
			Tarjan(Li[i].v);

			low[u]=min(low[u],low[Li[i].v]);
		}
		else
		{
			low[u]=min(low[u],dfn[Li[i].v]);
		}
	}

	if(low[u]==dfn[u])//強連通份量的根節點
	{

		while(!S.empty())
		{
			int v = S.top();

			S.pop();

			pre[v] = Num;//給份量集合標號

			G[Num].push_back(v);//記錄集合對應的點

			num[Num]++;

			if(v==u)
			{
				break;
			}
		}

		Num++;
	}

}

int main()
{

	int n,m;

	while(~scanf("%d %d",&n,&m))
	{
		top = 0;

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

		int u,v;

		for(int i=0;i<m;i++)
		{
			scanf("%d %d",&u,&v);

			AddEdge(u,v);
		}

		memset(dfn,-1,sizeof(dfn));
	
		memset(num,0,sizeof(num));

		for(int i =0;i<=n;i++)
		{
			G[i].clear();
		}

		dep = 0;Num = 0;

		for(int i=1;i<=n;i++)
		{
			if(dfn[i]==-1)
			{
				Tarjan(i);
			}
		}

		memset(Du,0,sizeof(Du));

		for(int i=0; i<Num ;i++) //判斷強連通份量的出度
		{
			memset(vis,false,sizeof(vis));

			for(int k=0;k<G[i].size();k++)
			{
				for(int j=Head[G[i][k]]; j!=-1;j=Li[j].next)
				{
					if(i!=pre[Li[j].v])
					{
						if(!vis[pre[Li[i].v]])//因爲不一樣的強連通份量之間相連的邊可能不止一條,因此要判斷是否是已經統計過。
						{
							vis[pre[Li[i].v]]=true;

							Du[i]++;
						}
					}
				}
			}
		}

		ans = 0;

		int ant  = 0;

		for(int i=0;i<Num;i++)//若是超過一個的出度爲零的強連通份量,則這些連通份量就不能被其餘的牛都仰慕。
		{
			if(Du[i]==0)
			{
				ans+=num[i];

				ant++;

			}
		}


		printf("%d\n",ant<=1?ans:0);

	}

	return 0;
}
相關文章
相關標籤/搜索