洛谷——P2341 [HAOI2006]受歡迎的牛//POJ2186:Popular Cows
阿新 • • 發佈:2018-08-28
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