[Bzoj1051][HAOI2006]受欢迎的牛(tarjan)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1051

由题意可知,被所有牛仰慕的牛之间也互相仰慕,则最后的答案一定是唯一的强连通分量,如图:

 

 

 

且这个强连通分量出度为0。

所以用tarjan缩环,然后在判断出度为0的是否有且仅有一个点。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 10010;
 5 struct node {
 6     int e, next;
 7 }edge[50010];
 8 int head[maxn * 20], len;
 9 void add(int s, int e) {
10     edge[++len].e = e;
11     edge[len].next = head[s];
12     head[s] = len;
13 }
14 int color[maxn], dfn[maxn], low[maxn], vis[maxn];
15 int out[maxn];
16 int num[maxn];
17 int dfsnum, ansnum, top;
18 stack<int>q;
19 void tarjan(int x) {
20     dfn[x] = low[x] = ++dfsnum;
21     vis[x] = 1;
22     q.push(x);
23     for (int i = head[x]; i; i = edge[i].next) {
24         int y = edge[i].e;
25         if (!dfn[y]) {
26             tarjan(y);
27             low[x] = min(low[x], low[y]);
28         }
29         else if (vis[y])
30             low[x] = min(low[x], dfn[y]);
31     }
32     if (low[x] == dfn[x]) {
33         ansnum++;
34         int y;
35         do {
36             y = q.top();
37             q.pop();
38             color[y] = ansnum;
39             num[ansnum]++;
40             vis[y] = 0;
41         } while (x != y);
42     }
43 }
44 int main() {
45     int n, m, x, y;
46     scanf("%d%d", &n, &m);
47     for (int i = 1; i <= m; i++) {
48         scanf("%d%d", &x, &y);
49         add(x, y);
50     }
51     for (int i = 1; i <= n; i++)
52         if (!dfn[i])
53             tarjan(i);
54     for (int x = 1; x <= n; x++) {
55         for (int i = head[x]; i; i = edge[i].next) {
56             int y = edge[i].e;
57             if (color[x] != color[y])
58                 out[color[x]]++;
59         }
60     }
61     int ans = 0, f = 0;
62     for (int i = 1; i <= ansnum; i++)
63         if (out[i] == 0)ans = num[i], f++;
64     if (f == 1)
65         printf("%d\n", ans);
66     else
67         printf("0\n");
68 }

 

posted @ 2019-07-01 20:40  祈梦生  阅读(...)  评论(... 编辑 收藏