1. 程式人生 > >POJ 2186 Popular Cows(強聯通分量)

POJ 2186 Popular Cows(強聯通分量)

!= href 任務 條件 cstring return col 現在 cst

題目鏈接:http://poj.org/problem?id=2186

題目大意:

每一頭牛的願望就是變成一頭最受歡迎的牛。現在有N頭牛,給你M對整數(A,B),表示牛A認為牛B受歡迎。 這 種關系是具有傳遞性的,如果A認為B受歡迎,B認為C受歡迎,那麽牛A也認為牛C受歡迎。你的任務是求出有多少頭 牛被所有的牛認為是受歡迎的。 解題思路: 假設有兩頭牛A和B都被其他所有牛認為是紅人,那麽顯然,A被B認為是紅人,B也被A認為是紅人,即存在一個包含A、B兩個頂點的圈,或者說,A、B同屬於一個強聯通分量。所以 如果有一頭牛被其他所有牛認為是紅人,那麽其所屬的強聯通分量內的所有牛都被其他所有牛認為是紅人。我們把圖進行強聯通分量分解後,至多有一個強聯通分量滿足題目的條件。 做法: 先用tarjan求出每個強連通分量,再縮點,統計每個點的出度,如果有且只有1個出度為0的點,就輸出這個點包含的節點數,否則輸出0。 代碼
 1
#include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 using namespace std; 8 const int N=1e4+5; 9 10 int cnt,num; 11 int dfn[N],low[N],fa[N],sze[N],outdeg[N]; 12 stack<int>sk;
13 vector<int>v[N]; 14 15 void tarjan(int u){ 16 dfn[u]=low[u]=++cnt; 17 sk.push(u); 18 for(int i=0;i<v[u].size();i++){ 19 int t=v[u][i]; 20 if(!dfn[t]){ //點t未被訪問 21 tarjan(t); 22 low[u]=min(low[u],low[t]);
23 } 24 else if(!fa[t]) low[u]=min(low[u],dfn[t]); //點t已被訪問,且t還在棧中 25 } 26 if(low[u]==dfn[u]){ 27 num++; 28 while(1){ 29 int t=sk.top(); 30 sk.pop(); 31 fa[t]=num; //縮點操作,將這些點都歸為點num 32 sze[num]++; 33 if(t==u) break; 34 } 35 } 36 } 37 38 int main(){ 39 int n,m; 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=m;i++){ 42 int a,b; 43 scanf("%d%d",&a,&b); 44 v[a].push_back(b); 45 } 46 for(int i=1;i<=n;i++){ 47 if(!dfn[i]) tarjan(i); 48 } 49 for(int i=1;i<=n;i++){ 50 for(int j=0;j<v[i].size();j++){ 51 int t=v[i][j]; 52 if(fa[t]!=fa[i]) outdeg[fa[i]]++; 53 } 54 } 55 //縮點後,出度為0的點只能有一個,否則不符合條件輸出0 56 int ans=0; 57 for(int i=1;i<=num;i++){ 58 if(!outdeg[i]){ 59 if(ans>0){ 60 puts("0"); 61 return 0; 62 } 63 ans=sze[i]; 64 } 65 } 66 printf("%d\n",ans); 67 return 0; 68 }

POJ 2186 Popular Cows(強聯通分量)