题意:奶牛之间的崇拜具有传递性(刚上完离散数学发出小草的声音.mp3),给出一些崇拜关系,求是否存在奶牛被所有奶牛崇拜。如果存在,输出奶牛的数量。
解:如果奶牛之间形成一个环,它们互相崇拜;如果这个环中的奶牛被其余奶牛崇拜,那么它们被所有奶牛崇拜。所以一个环可视作一个点,如果从所有点均可到达这个点,那么输出这个点的大小。所以先缩点。缩完点判断哪些点能被其余所有点到达。n方肯定是会超时的。现在这张图上没有了环,可以看作一棵或多棵树(多棵肯定不行),这棵树只能有一个叶子结点,也就是没有出度。每个点遍历一遍出边,顺带一提因为只要排除掉它所在环里的点,新图其实不用建立。
代码:
1 #include <algorithm> 2 #include <stack> 3 #include <vector> 4 #include <stdio.h> 5 using namespace std; 6 #define maxx 10005 7 #define maxn 10005 8 #define maxm 50005 9 #define inf 0x3f3f3f3f 10 int n,m; 11 vector<int> e[maxm]; 12 int dfn[maxn]={0},low[maxn]={0}; 13 int cnt=0,vis[maxn]={0}; 14 int colornum=0,color[maxn]={0},num[maxn]={0}; 15 stack<int> s; 16 int out[maxn]; 17 void paint(int x){ 18 s.pop(); 19 vis[x]=1; 20 color[x]=colornum; 21 num[colornum]++; 22 } 23 void tarjan(int now){ 24 dfn[now]=low[now]=++cnt; 25 s.push(now); 26 vis[now]=1; 27 for(int i=0;i<e[now].size();i++){ 28 int to=e[now][i]; 29 if(!dfn[to]) { 30 tarjan(to); 31 low[now]=min(low[now],low[to]); 32 } 33 else if(vis[to]) 34 low[now]=min(low[now],dfn[to]); 35 } 36 if(low[now]==dfn[now]){ 37 colornum++; 38 while(s.top()!=now) 39 paint(s.top()); 40 paint(now); 41 } 42 } 43 signed main() { 44 scanf("%d%d",&n,&m); 45 for(int i=0;i<m;i++){ 46 int x,y; 47 scanf("%d%d",&x,&y); 48 e[x].push_back(y); 49 } 50 for(int i=1;i<=n;i++) { 51 if (!dfn[i]) 52 tarjan(i); 53 } 54 for(int i=1;i<=n;i++){ 55 for(int j=0;j<e[i].size();j++){ 56 int to=e[i][j]; 57 if(color[to]!=color[i]) 58 out[color[i]]++; 59 } 60 } 61 int ans=0; 62 for(int i=1;i<=colornum;i++) 63 if(!out[i]){ 64 if(ans==0) 65 ans=num[i]; 66 else ans=-1; 67 } 68 printf("%d\n",ans==-1?0:ans); 69 return 0; 70 }