P2341 [HAOI2006]受欢迎的牛(tarjan+缩点)

P2341 [HAOI2006]受欢迎的牛

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果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,如果他有出度,设他支持a,这已经是有个大点(缩点)了,大点内所有的点都可以相互支持,然后大点又支持a(a不在大点内),且a一定不支持这个大点(如果a支持大点,a在这个大点(被缩点)内),所以一定要找没有出度的点;
  • 只能找一个,如果有两个或以上,那么就一个明星也没有,我们假设两个点x,y没有出度,既然x,y都没有出度,x点就不支持y,y也不支持x,所以就没有没有明星,(一个出度为零的点无法到达另一个出度为零的点,都没有出度了,哪来的“到达”呢?)

 code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<stack>
 4 using namespace std;
 5 
 6 const int MAXN = 10100;
 7 struct Edge{
 8     int to,nxt;
 9 }e[100100];
10 int head[MAXN],dfn[MAXN],low[MAXN],bel[MAXN],sz[MAXN],pd[MAXN],x[50010],y[50010];
11 bool vis[MAXN];
12 int cnt,n,m,tot,num,ans,flag;
13 stack<int>s;
14 
15 void add(int u,int v)
16 {
17     ++cnt;
18     e[cnt].to = v;
19     e[cnt].nxt = head[u];
20     head[u] = cnt;
21 }
22 void tarjan(int u)
23 {
24     low[u] = dfn[u] = ++tot;
25     s.push(u);
26     vis[u] = true ;
27     for (int i=head[u]; i; i=e[i].nxt)
28     {
29         int v = e[i].to;
30         if (!dfn[v])
31         {
32             tarjan(v);
33             low[u] = min(low[u],low[v]);
34         }
35         else if (vis[v]) low[u] = min(low[u],dfn[v]);
36     }
37     if (dfn[u]==low[u])
38     {
39         int now = -1;
40         num++;
41         while (now!=u)
42         {
43             now = s.top();
44             s.pop();
45             bel[now] = num;
46             sz[num]++;
47             vis[now] = false ;
48         }
49     }
50 }
51 int main()
52 {
53     scanf("%d%d",&n,&m);
54     for (int i=1; i<=m; ++i)
55     {
56         scanf("%d%d",&x[i],&y[i]);
57         add(x[i],y[i]);
58     }
59     for (int i=1; i<=n; ++i)
60         if (!dfn[i]) tarjan(i);
61     
62     for (int i=1; i<=m; ++i)
63         if (bel[x[i]]!=bel[y[i]])
64             pd[bel[x[i]]]++;
65     
66     for (int i=1; i<=num; ++i)
67         if (!pd[i])
68             flag++, ans = sz[i];
69             
70     if (flag==1) printf("%d",ans);
71     else printf("0");
72     return 0;
73 }
原文地址:https://www.cnblogs.com/mjtcn/p/7143162.html