1. 程式人生 > >bzoj 1051: [HAOI2006]受歡迎的牛 (Tarjan 縮點)

bzoj 1051: [HAOI2006]受歡迎的牛 (Tarjan 縮點)

scan top www stack namespace bsp tac problem ons

鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=1051

思路: 首先用Tarjan把環縮成點,要想收到所有人的歡迎,那麽這個點的出度必為0,且只能有一個出度為0的,如果有多個的話那麽沒有點會收到所有人歡迎,我們找到這個點,這個點可能是縮完點後的點,我們找下這個點代表的環中點的數量。

實現代碼:

#include<bits/stdc++.h>
using namespace std;

const int M = 5e4+10;
vector<int>g[M];
stack<int>s;
int dfn[M],low[M],vis[M],in
[M],out[M],cnt,num,scc[M]; void Tarjan(int u){ dfn[u] = low[u] = ++cnt;vis[u] = 1; s.push(u); for(int i = 0;i < g[u].size();i ++){ int v = g[u][i]; if(!vis[v]) Tarjan(v),low[u] = min(low[u],low[v]); else low[u] = min(low[u],dfn[v]); } if(low[u] == dfn[u]){ num
++; int now; do{ now = s.top(); s.pop(); scc[now] = num; } while(!s.empty()&&now!=u); } } int main() { int n,m,u,v; scanf("%d%d",&n,&m); for(int i = 1;i <= m;i ++){ scanf("%d%d",&u,&v); g[u].push_back(v); }
for(int i = 1;i <= n;i ++){ if(!vis[i]) Tarjan(i); } for(int i = 1;i <= n;i ++){ for(int j = 0;j < g[i].size();j ++){ int v = g[i][j]; if(scc[i] != scc[v]){ out[scc[i]]++; in[scc[v]]++; } } } int k = 0,ans = 0,tag; for(int i = 1;i <= num;i ++){ if(!out[i]){ k++; tag = i; } } if(k == 1){ for(int i = 1;i <= n;i ++) if(scc[i] == tag) ans++; printf("%d\n",ans); } else printf("0\n"); return 0; }

bzoj 1051: [HAOI2006]受歡迎的牛 (Tarjan 縮點)