[BZOJ1051] [HAOI2006] 受欢迎的牛 (强联通分量)

Posted CtrlCV

tags:

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

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

Solution

  首先Tarjan缩点,那么一定有至少一个点没有出边。

  如果没有出边的点只有一个,那么其他点都直接或间接指向这个点。

  如果有多个,那么这几个无出边的点相互无边相连。

  答案就是该点表示的强联通分量里的点的个数。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct edge
 4 {
 5     int u, v, nxt;
 6 }e[100005];
 7 stack<int> S;
 8 int dfn[10005], low[10005], belong[10005], cnt1, cnt2;
 9 int ins[10005], fst[2][10005], outd[10005], siz[10005];
10  
11 void addedge(int i, int *x, int u, int v)
12 {
13     e[i] = (edge){u, v, x[u]}, x[u] = i;
14 }
15  
16 void Tarjan(int u)
17 {
18     int v;
19     dfn[u] = low[u] = ++cnt1;
20     S.push(u), ins[u] = true;
21     for(int i = fst[0][u]; i; i = e[i].nxt)
22         if(!dfn[e[i].v])
23         {
24             Tarjan(e[i].v);
25             low[u] = min(low[u], low[e[i].v]);
26         }
27         else if(ins[e[i].v])
28             low[u] = min(low[u], low[e[i].v]);
29     if(dfn[u] == low[u])
30     {
31         ++cnt2;
32         do
33         {
34             v = S.top(), S.pop(), ins[v] = false;
35             belong[v] = cnt2, ++siz[cnt2];
36         }
37         while(u != v);
38     }
39 }
40  
41 int main()
42 {
43     int n, m, u, v, ans = -1;
44     cin >> n >> m;
45     for(int i = 1; i <= m; ++i)
46     {
47         cin >> u >> v;
48         addedge(i, fst[0], u, v);
49     }
50     for(int i = 1; i <= n; ++i)
51         if(!dfn[i]) Tarjan(i);
52     for(int i = 1; i <= m; ++i)
53     {
54         u = belong[e[i].u], v = belong[e[i].v];
55         if(u != v)
56         {
57             addedge(i + m, fst[1], u, v);
58             ++outd[u];
59         }
60     }
61     for(int i = 1; i <= cnt2; ++i)
62         if(!outd[i]) ans = ~ans ? 0 : siz[i];
63     cout << ans << endl;
64     return 0;
65 }
View Code

 

以上是关于[BZOJ1051] [HAOI2006] 受欢迎的牛 (强联通分量)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1051 [HAOI2006]受欢迎的牛

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

BZOJ 1051: [HAOI2006]受欢迎的牛

bzoj1051: [HAOI2006]受欢迎的牛

bzoj 1051: [HAOI2006]受欢迎的牛

BZOJ 1051: [HAOI2006]受欢迎的牛