1. 程式人生 > >POJ2186 Popular Cows Kosaraju

POJ2186 Popular Cows Kosaraju

題目大意是:在一個牧群中,有N個奶牛,給定M對關係(A,B)表示A仰慕B,而且仰慕關係有傳遞性,問被所有奶牛(除了自己)仰慕的奶牛個數


因為仰慕關係具有傳遞性,因此在一個強連通分量中,每個奶牛都被分量中的其他奶牛膜拜,而且也膜拜著分量中的其他奶牛,這種互相膜拜的場景在現實生活中也是經常存在的,因此,本題可以將強連通分量縮點,並構造新圖,最後做一次掃描,統計出度為0的點的個數,如果正好為1,表示這個強連通分量(可能是一個點,也可能是多個點)中的奶牛都符合條件,輸出其中的個數即可。
如果不唯一,顯然就沒有奶牛符合被所有奶牛膜拜的條件了。

#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#define INF 99999999
using namespace std;
int n, m;
int num[10005];//第i個強連通分量包含的個數
bool P[10005];//DFS判重 
int flag[10005];//該點是屬於第幾個強連通分量
vector<int> v[10005];//正向圖
vector<int> rv[10005];//反向圖
vector<int> s;
int cnt;

void dfs1(int x){
	P[x] = 1;
	for (int i = 0; i < v[x].size(); i++)
		if (!P[v[x][i]])
			dfs1(v[x][i]);
	s.push_back(x);
}

void dfs2(int x){
	flag[x] = cnt;
	num[cnt]++;
	P[x] = 1;
	for (int i = 0; i < rv[x].size(); i++)
		if (!P[rv[x][i]])
			dfs2(rv[x][i]);
}

void Kosaraju(){
	memset(P, 0, sizeof(P));
	for (int i = 1; i <= n; i++)	{
		for (int j = 0; j < v[i].size(); j++){//檢查強連通分量是否有出度,有就對應的P[i]=1  		
			int w = v[i][j];
			if (flag[i] != flag[w])
				P[flag[i]] = 1;//這個強連通分量標記為1
		}
	}

	int ans;
	int t = 0;
	for (int i = 1; i <= cnt; i++){//檢查有幾個強連通分量的出度為0	
		if (!P[i]){		
			ans = i;
			t++;
		}
	}

	if (t == 1)//如果只有一個強連通分量的入度為0,則輸出應的tree_n[i]為要的答案,否則沒有
		printf("%d\n", num[ans]);
	else
		printf("0\n");
}

int main(){
	int a, b;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++){
		scanf("%d%d", &a, &b);
		v[a].push_back(b);
		rv[b].push_back(a);
	}

	for (int i = 1; i <= n; i++)
		if (!P[i])
			dfs1(i);
	
	memset(P, 0, sizeof(P));
	memset(num, 0, sizeof(num));
	cnt = 0;
	for (int i = s.size() - 1; i >= 0; i--){
		if (!P[s[i]]){
			cnt++;
			dfs2(s[i]);
		}
	}

	Kosaraju();

	return 0;
}