题解 P2996 [USACO10NOV]Visiting Cows G

题目描述

Link

给定一棵 \(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;
}
posted @ 2021-02-25 09:20  recollector  阅读(65)  评论(0编辑  收藏  举报