题解 P2996 [USACO10NOV]Visiting Cows G
题目描述
给定一棵 \(n\) 个节点树,在一条边的两个端点只能选一个点的前提下,求最多能选多少个点。
\(1 \leq n \leq 5\times 10^4\) 。
Solution
和没有上司的舞会是一样的,只不过这题点权都是 \(1\) 。在,为什么评绿?
考虑 \(dp\) ,设 \(f_{i,0/1}\) 表示在以 \(i\) 为根的子树中,不选 \(/\) 选 \(i\) 这个节点所能选择的最大节点。
首先,如果不选 \(i\) ,那么 \(i\) 的儿子可以选也可以不选:
\[f_{i,0} = \sum_{j \in son(i)} \max\{f_{j,0} ,f_{j,1}\}
\]
如果选了 \(i\) ,那么 \(i\) 的所有儿子都不能选,也就是说:
\[f_{i,1}=1 + \sum_{j\in son(i)} f_{j,0}
\]
直接 \(dp\) 就可以,复杂度 \(\mathcal{O}(n)\) 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
inline int read() {
int num = 0 ,f = 1; char c = getchar();
while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar();
while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar();
return num * f;
}
inline int max(int a ,int b) {return a > b ? a : b;}
const int N = 5e4 + 5 ,M = 1e5 + 5 ,INF = 0x3f3f3f3f;
struct Edge {
int to ,next;
Edge (int to = 0 ,int next = 0) :
to(to) ,next(next) {}
}G[M]; int head[N] ,cnt;
inline void add(int u ,int v) {
G[++cnt] = Edge(v ,head[u]); head[u] = cnt;
G[++cnt] = Edge(u ,head[v]); head[v] = cnt;
}
int f[N][2];
inline void dfs(int now ,int fa) {
f[now][1] = 1;
for (int i = head[now]; i ; i = G[i].next) {
int v = G[i].to;
if (v == fa) continue;
dfs(v ,now);
f[now][1] += f[v][0];
f[now][0] += max(f[v][1] ,f[v][0]);
}
}
int n;
signed main() {
n = read();
for (int i = 1; i <= n - 1; i++) {
int u = read() ,v = read();
add(u ,v);
}
dfs(1 ,0);
printf("%d\n" ,max(f[1][0] ,f[1][1]));
return 0;
}