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