BZOJ10511051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点

Posted DMoon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ10511051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点相关的知识,希望对你有一定的参考价值。

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

 

Source

 

 1A啦啦啦~ 新姿势tarjan算法(现在才学太弱啦!),tarjan算法求完强连通分量后进行缩点,然后查找出度为0的唯一的点(缩的点),为什么是唯一的,很简单,因为其他点都有出度,也就是其他所有点都连在一起指向该点,若不唯一,就误无解。
技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <queue>
 5 #include <stack>
 6 #define N 10010
 7 #define M 50050
 8 using namespace std;
 9 struct data1{int p,next;}e[M];
10 int ans,cnt,n,m,scc;
11 int head[N],dfn[N],low[N],vis[N],inq[N],h[N],belong[N],ringsum[N];
12 stack<int> q;
13 void se(int x,int y){cnt++;e[cnt].next=head[x];head[x]=cnt;e[cnt].p=y;}
14 void Tarjan(int x)
15 {
16     vis[x]=inq[x]=1;
17     low[x]=dfn[x]=++cnt;;
18     q.push(x);
19     for (int i=head[x];i!=-1;i=e[i].next)
20     {
21         if (!vis[e[i].p])
22         {
23             Tarjan(e[i].p);
24             low[x]=min(low[x],low[e[i].p]);
25         }
26         else if (inq[e[i].p])    low[x]=min(low[x],low[e[i].p]);
27     }
28     if (dfn[x]==low[x])
29     {
30         int now;
31         scc++;
32         while (now!=x)
33         {
34             now=q.top();q.pop();
35             belong[now]=scc;
36             inq[now]=0;
37             ++ringsum[scc];
38         }
39     }
40 }
41 void part1_tarjan()
42 {
43     cnt=0;
44     for (int i=1;i<=n;i++)
45         if (!vis[i])
46             Tarjan(i);
47 }
48 void part2_shr_point()
49 {
50     for (int i=1;i<=n;i++)
51         for (int t=head[i];t!=-1;t=e[t].next)
52             if (belong[i]!=belong[e[t].p])
53                 h[belong[i]]=1;
54 }
55 void part3_doit()
56 {
57     for (int i=1;i<=scc;i++)
58         if (!h[i])
59         {
60             if (ans)
61             {
62                 ans=0;
63                 return;
64             }
65             else    ans=ringsum[i];
66         }
67 }
68 int main()
69 {
70     memset(e,-1,sizeof(e));
71     memset(head,-1,sizeof(head));
72     scanf("%d%d",&n,&m);
73     for (int i=1;i<=m;i++)
74     {
75         int x,y;
76         scanf("%d%d",&x,&y);
77         se(x,y);
78     }
79     part1_tarjan();
80     part2_shr_point();
81     part3_doit();
82     printf("%d\n",ans);
83     return 0;
84 }
View Code

 

以上是关于BZOJ10511051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1051 [HAOI2006]受欢迎的牛

[BZOJ] 1051: [HAOI2006]受欢迎的牛

BZOJ 1051: [HAOI2006]受欢迎的牛

bzoj1051 [HAOI2006]受欢迎的牛

bzoj1051: [HAOI2006]受欢迎的牛

bzoj 1051: [HAOI2006]受欢迎的牛