[HAOI2006]受欢迎的牛

[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

这道题已经搁了一个多月了,今天终于决定做它了(主要是终于想到要搞一搞tarjan了)。首先tarjan缩点,如果两个强连通分量有连边,重新建边,如果一个强连通分量能被其他所有强连通分量抵达,那么该强连通分量中的所有点都是“明星”。这时候很容易发现一个简单的结论:图中当且仅当一个强连通分量的出度为0时,该强连通分量中所有的点都是“明星”。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int n,m,x1[1000001],y1[1000001],sum,ans,num;
 6 int belong[10000001],time,top;
 7 int head[10000001],tot,sta[10000001],number[1000001],headd[100001];
 8 int dfn[1000001],low[1000001],vis[1000001],dis[10000001];
 9 struct node{
10     int to;
11     int next;
12 }mp[1000001],mp2[1000001];
13 void add(int u,int v)
14 {
15     mp[++tot].to=v;
16     mp[tot].next=head[u];
17     head[u]=tot;
18 }
19 void add2(int u,int v)
20 {
21     mp2[++tot].to=v;
22     mp2[tot].next=headd[u];
23     headd[u]=tot;
24 }
25 void tarjan(int x)
26 {
27     dfn[x]=low[x]=++time;
28     sta[++top]=x;
29     vis[x]=1;
30     for(int i=head[x];i;i=mp[i].next)
31     {
32         int v=mp[i].to;
33         if(!dfn[v])
34         {
35             tarjan(v);
36             low[x]=min(low[x],low[v]);
37         }
38         else if(vis[v]) low[x]=min(low[x],dfn[v]);
39     }
40     if(low[x]==dfn[x])
41     {
42         ++num;
43         vis[x]=0;
44         while(sta[top+1]!=x)
45         {
46             belong[sta[top]]=num;
47             number[num]++;//记录下每个强连通分量中点的个数
48             vis[sta[top]]=0;
49             top--;
50         }
51     }
52 }
53 void work() 
54 {
55     int du=0,s=0;
56     for(int i=1;i<=num;i++)
57     if(!headd[i]) 
58     {
59       du++;
60       s=i;
61     }
62     if(du==1) //满足结论输出答案 
63     {
64       cout<<number[s]<<endl;
65       return;
66     }
67     cout<<0<<endl;
68     return;
69 }
70 int main()
71 {
72     scanf("%d%d",&n,&m);
73     for(int i=1;i<=m;i++)
74     {
75         scanf("%d%d",&x1[i],&y1[i]);
76         add(x1[i],y1[i]);
77     }
78     for(int i=1;i<=n;i++)
79     {
80         if(!dfn[i]) tarjan(i);
81      }
82      tot=0;
83      for(int i=1;i<=m;i++)
84      {
85          if(belong[x1[i]]!=belong[y1[i]])
86          add2(belong[x1[i]],belong[y1[i]]);//重新建边 
87     }
88      work();
89      return 0; 
90 }
原文地址:https://www.cnblogs.com/drurry/p/7787772.html