【tarjan+缩点】BZOJ1051-受欢迎的牛
【题意】
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
【思路】
存在于首页的经典老题,之前POJ的那道题做过之后无压力1A水过。
先用tarjan将所有联通分量进行缩点,缩点后考虑出度为0的点的个数:
(1)个数大于1的时候,显然不存在受欢迎的牛!
(2)个数等于0的时候,假设有一头牛X是受欢迎的,那么它必定有喜欢的牛Y,而它又收到牛Y的欢迎,说明存在环,不是DAG图,矛盾!
(3)个数等于1的时候,用数学归纳法推一下,有这样一个结论:出度为0的那个点可以被其它所有点到达。
有了这样的结论,直接做就可以了XD
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<vector> 6 #include<stack> 7 #include<cmath> 8 #include<algorithm> 9 const int MAXN=10000+500; 10 const int MAXM=50000+500; 11 using namespace std; 12 int vis[MAXN],instack[MAXN]; 13 int u[MAXM],v[MAXM]; 14 int b[MAXN],sum[MAXN]; 15 int dfn[MAXN],low[MAXN]; 16 vector<int> E[MAXN]; 17 stack<int> S; 18 int n,m; 19 int cnt=-1,T=0; 20 21 void tarjan(int u) 22 { 23 dfn[u]=low[u]=++T; 24 vis[u]=1; 25 S.push(u); 26 instack[u]=1; 27 28 for (int i=0;i<E[u].size();i++) 29 { 30 int son=E[u][i]; 31 if (!vis[son]) 32 { 33 tarjan(son); 34 low[u]=min(low[son],low[u]); 35 } 36 else 37 if (vis[son] && instack[son]) 38 low[u]=min(dfn[son],low[u]); 39 } 40 41 if (dfn[u]==low[u]) 42 { 43 cnt++; 44 int x; 45 do 46 { 47 x=S.top(); 48 S.pop(); 49 sum[cnt]++; 50 b[x]=cnt; 51 instack[x]=0; 52 }while (x!=u); 53 } 54 } 55 56 void init() 57 { 58 memset(vis,0,sizeof(vis)); 59 memset(sum,0,sizeof(sum)); 60 memset(instack,0,sizeof(instack)); 61 scanf("%d%d",&n,&m); 62 for (int i=0;i<m;i++) 63 { 64 scanf("%d%d",&u[i],&v[i]); 65 E[u[i]].push_back(v[i]); 66 } 67 } 68 69 void solve() 70 { 71 int out[MAXN]; 72 memset(out,0,sizeof(out)); 73 for (int i=0;i<m;i++) 74 if (b[u[i]]!=b[v[i]]) 75 { 76 out[b[u[i]]]++; 77 } 78 79 int noout=0; 80 int res; 81 for (int i=0;i<=cnt;i++) 82 if (out[i]==0) 83 { 84 res=i; 85 noout++; 86 } 87 if (noout==1) cout<<sum[res]<<endl; 88 else cout<<0<<endl; 89 } 90 91 int main() 92 { 93 init(); 94 for (int i=1;i<=n;i++) if (vis[i]==0) tarjan(i); 95 solve(); 96 return 0; 97 }