1. 程式人生 > >洛谷——P2341 [HAOI2006]受歡迎的牛//POJ2186:Popular Cows

洛谷——P2341 [HAOI2006]受歡迎的牛//POJ2186:Popular Cows

return item popular 空格 getch ++ 整數 getchar() define

P2341 [HAOI2006]受歡迎的牛/POJ2186:Popular Cows

題目背景

本題測試數據已修復。

題目描述

每頭奶牛都夢想成為牛棚裏的明星。被所有奶牛喜歡的奶牛就是一頭明星奶牛。所有奶

牛都是自戀狂,每頭奶牛總是喜歡自己的。奶牛之間的“喜歡”是可以傳遞的——如果A喜

歡B,B喜歡C,那麽A也喜歡C。牛欄裏共有N 頭奶牛,給定一些奶牛之間的愛慕關系,請你

算出有多少頭奶牛可以當明星。

輸入輸出格式

輸入格式:

? 第一行:兩個用空格分開的整數:N和M

? 第二行到第M + 1行:每行兩個用空格分開的整數:A和B,表示A喜歡B

輸出格式:

? 第一行:單獨一個整數,表示明星奶牛的數量

輸入輸出樣例

輸入樣例#1: 復制
3 3
1 2
2 1
2 3
輸出樣例#1: 復制
1

說明

只有 3 號奶牛可以做明星

【數據範圍】

10%的數據N<=20, M<=50

30%的數據N<=1000,M<=20000

70%的數據N<=5000,M<=50000

100%的數據N<=10000,M<=50000

解題報告:

題目大意:給定一個有向圖,求有多少個頂點是由任何頂點出發都可達的。

有用的定理:有向無環圖中唯一出度為0的點,一定可 以由任何點出發均可達(由於無環,所 以從任何點出發往前走,必然終止於 一個出度為0的點)

思路:tarjan縮點,判斷強聯通分量的出度為0即可,若出度為0的聯通分量的個數>1,則這些點互相不可到達,原問題無解,反之輸出聯通分量裏的點數即可。

#include<bits/stdc++.h>
#define N 100000

using namespace std;

void in(int &x){
    char c=getchar();x=0;int f=1;
    while(!isdigit(c)){if(c==-) f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-0;c=getchar();}
    x
*=f; } struct node{ int to,next; }e[N]; int n,m,head[N],cnt,tot,dfn[N],low[N],item,belong[N],all[N],du[N]; stack<int>S; bool vis[N]; void add(int u,int v){ e[++tot].to=v;e[tot].next=head[u];head[u]=tot; } void tarjan(int u){ dfn[u]=low[u]=++item; S.push(u);vis[u]=1; for(int i=head[u],v;i,v=e[i].to;i=e[i].next){ if(!dfn[v]){ tarjan(v); low[u]=min(low[v],low[u]); }else if(vis[v]){ low[u]=min(low[u],dfn[v]); } }if(dfn[u]==low[u]){ int v=u;++cnt; do{ v=S.top();S.pop(); vis[v]=false; belong[v]=cnt;all[cnt]++; }while(v!=u); } } int main() { in(n);in(m); for(int i=1;i<=m;i++){ int u,v; in(u);in(v); add(u,v); }for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); //記錄出度 for(int i=1;i<=n;i++){ for(int j=head[i],v;j,v=e[j].to;j=e[j].next){ if(belong[i]!=belong[v]){ du[belong[i]]++; } } } int an=0; for(int i=1;i<=cnt;i++){ if(!du[i]) { if(an) {puts("0");return 0;} an=i; } }printf("%d\n",all[an]); return 0; }

洛谷——P2341 [HAOI2006]受歡迎的牛//POJ2186:Popular Cows