Popular Cows
OpenJ_Bailian - 2186题目大意是有n头牛,他们有m对特殊的关系
关系A B表示A仰慕B 恩 是感觉怪怪的= =
然后如果A仰慕B B仰慕C 那么A也仰慕C 也就是关系是可传递的
要求找出被其他牛都仰慕的牛的数目
一开始很费解,要不是放在强连通里,实在没法往这方向靠……
其实反过来想的话比较好像,强连通分支的定义——强连通分支中从任何一个点都可以访问到其余各点(有向图)
这样再回到题中 可以得出两个结论
1.如果某个强联通分支中的某只牛被分支外的所有牛都仰慕,也就是说分支外的牛都有一条通向他的路,和他在同一个强连通分支里的所有牛也是满足要求的。
2.如果分支中有某头牛仰慕分支外的牛,那么就不存在被所有牛都仰慕的牛。(可以换种方式来想,如果分支中某头牛仰慕分支外的牛,还被其余牛都仰慕,那么分支外的这头牛也应该被包含在分支内。因为这样就说明分支外的那头牛,会有一条通向分支内的路径,也就是符合强连通分量的定义)
3.经2结论可知,出度为0的强连通分支,就是满足条件的牛群。但如果有两群,就不存在这种牛。因为两个分支间是没有关系的。可以自己画一画看看。
找到方法判断就好办了,首先把所有的强连通分支求出来,缩点后变成一团团的。找出出度为0的缩点。如果存在两个或两个以上,答案就是0。如果之存在一个,那么这个点中的所有牛都是满足题意的牛,统计输出即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 50005; vector<vector<int> >G; int low[maxn],dfn[maxn],color[maxn],stk[maxn]; bool instack[maxn]; int in[maxn],out[maxn]; int top,ti,cnt,n,m,sum,temp; void tarjan(int u) { int v; low[u]=dfn[u]=++ti; stk[top++]=u; instack[u]=1; for(int i=0; i<G[u].size(); i++) { v=G[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { cnt++; do { v=stk[--top]; instack[v]=false; color[v]=cnt; } while(v!=u); } } void solve() { memset(instack,0,sizeof(instack)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(color,0,sizeof(color)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); top=ti=cnt=sum=0; for(int i=1; i<=n; i++) if(dfn[i]==0) { tarjan(i); } for(int i=1; i<=n; i++) for(int j=0; j<G[i].size(); j++) { int nextone=G[i][j]; if(color[i]!=color[nextone]) out[color[i]]++; } for(int i=1; i<=cnt; i++) if(out[i]==0) { sum++; temp=i; } if(sum==1) { int ans=0; for(int i=1; i<=n; i++) { if(color[i]==temp) ans++; } cout<<ans<<endl; } else { cout<<0<<endl; } } int main() { int x,y; while(cin>>n>>m) { G.clear(); G.reserve(n+1); while(m--) { cin>>x>>y; G[x].push_back(y); } solve(); } return 0; }