【BZOJ 1051】[HAOI2006]受欢迎的牛
1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3375 Solved: 1771
[Submit][Status][Discuss]
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
ANALYSIS
我的思路很简单很暴力,先把环缩点变成DAG,然后按拓扑序递推支持人数。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 10005; const int MAXM = 50005; struct Edge { int from, to, next; Edge() { } Edge(int u, int v) : from(u), to(v) { } }edges[MAXM], edt[MAXM]; int n, m; int first[MAXN], ft[MAXN], sccno[MAXN], dg[MAXN], bkn[MAXN], scc_cnt; int topsort[MAXN], f[MAXN], toplen; bool vis[MAXN]; void dfs1(int u) { if (!vis[u]) return; vis[u] = false; for (int i = first[u]; i != -1; i = edges[i].next) dfs1(edges[i].to); topsort[toplen++] = u; } void dfs2(int u) { if (sccno[u]) return; sccno[u] = scc_cnt; bkn[scc_cnt]++; for (int i = first[u]; i != -1; i = edges[i].next) dfs2(edges[i].to); } void dfs3(int u) { if (!vis[u]) return; vis[u] = false; topsort[toplen++] = u; for (int i = ft[u]; i != -1; i = edt[i].next) { Edge &e = edt[i]; dg[e.to]--; if (dg[e.to] == 0) dfs3(e.to); } } int main() { scanf("%d%d", &n, &m); memset(first, -1, sizeof(first)); for (int i = 0; i < m; ++i) { int a, b; scanf("%d%d", &a, &b); edges[i] = Edge(a, b); edges[i].next = first[a]; first[a] = i; } memset(vis, true, sizeof(vis)); scc_cnt = toplen = 0; for (int i = 1; i <= n; ++i) dfs1(i); memset(sccno, 0, sizeof(sccno)); memset(bkn, 0, sizeof(bkn)); for (int i = 0; i < n; ++i) if (!sccno[topsort[i]]) { scc_cnt++; dfs2(topsort[i]); } memset(dg, 0, sizeof(dg)); memset(ft, -1, sizeof(ft)); int tots = 0; for (int i = 1; i <= n; ++i) for (int j = first[i]; j != -1; j = edges[j].next) { Edge &e = edges[j]; if (sccno[i] != sccno[e.to]) { edt[tots] = Edge(sccno[i], sccno[e.to]); edt[tots].next = ft[sccno[i]]; ft[sccno[i]] = tots++; dg[sccno[e.to]]++; } } memset(vis, true, sizeof(vis)); toplen = 0; for (int i = 1; i <= scc_cnt; ++i) if (dg[i] == 0) dfs3(i); memset(f, 0, sizeof(f)); for (int i = 0; i < scc_cnt; ++i) for (int j = ft[topsort[i]]; j != -1; j = edt[j].next) { Edge &e = edt[j]; f[e.to] += f[topsort[i]] + bkn[topsort[i]]; } int ans = 0; for (int i = 1; i <= n; ++i) if (f[sccno[i]] + bkn[sccno[i]] >= n) ans++; printf("%d\n", ans); return 0; }