[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 }