【tarjan】BZOJ 1051:受欢迎的牛

1051: [HAOI2006]受欢迎的牛

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3134  Solved: 1642
[Submit][Status][Discuss]

Description

每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

Input

第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)

Output

一个数,即有多少头牛被所有的牛认为是受欢迎的。

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

HINT

 

100%的数据N<=10000,M<=50000

  很久之前做过的一道题目。。
  具体就是先tarjan缩点,点的权值就是这个连通分量的点的数量
  然后找入度为0的点
  只有一个就输出它的权值
  多个就输0
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 
 6 #define maxn 10001
 7 
 8 using namespace std;
 9 
10 inline int In()
11 {
12     int x=0;char ch=getchar();
13     while(ch<'0'||ch>'9')ch=getchar();
14     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
15     return x;
16 }
17 
18 struct ed{
19     int u,v;
20 }edge[maxn*5];
21 
22 struct node{
23     int to,last;
24 }e[maxn*10];
25 
26 int last[maxn],tot=0,dfn[maxn],low[maxn],father[maxn],sta[maxn],top=0,cnt=0,size=0,num[maxn],in[maxn];
27 
28 bool ins[maxn];
29 
30 void add(int u,int v){e[++tot].to=v,e[tot].last=last[u],last[u]=tot;}
31 
32 void tarjan(int poi)
33 {
34     dfn[poi]=low[poi]=++cnt;
35     ins[poi]=1;sta[++top]=poi;
36     for(int i=last[poi];i;i=e[i].last)
37     {
38         int u=e[i].to;
39         if(!dfn[u])
40         {
41             tarjan(u);
42             low[poi]=min(low[u],low[poi]);
43         }
44         else if(ins[u]) low[poi]=min(low[poi],dfn[u]);
45     }
46     if(dfn[poi]==low[poi])
47     {
48         size++;
49         int vv;
50         do{
51             vv=sta[top];
52             father[vv]=size;
53             ins[vv]=0;
54             num[size]++;
55             top--;
56         }while(vv!=poi);
57     }
58 }
59 
60 int main()
61 {
62     freopen("1051.in","r",stdin);
63     int n,m,str=0;
64     n=In(),m=In();
65     for(int i=1;i<=n;i++)father[i]=i;
66     for(int i=1;i<=m;i++)
67         edge[i].u=In(),edge[i].v=In(),add(edge[i].u,edge[i].v);
68     for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
69     memset(last,0,sizeof(last));
70     tot=0;
71     for(int i=1;i<=m;i++)if(father[edge[i].u]!=father[edge[i].v]){
72         in[father[edge[i].u]]++;
73     }
74     for(int i=1;i<=size;i++)
75     {
76         if(!in[i]&&str){printf("0");return 0;}
77         if(!in[i])str=i;
78     }
79     printf("%d",num[str]);
80     return 0;
81 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值