题目描述
输入格式 1784.in
输出格式 1784.out
输入样例 1784.in
输出样例 1784.out
我们来分析一下样例:
三个叶子结点的情况是显然的,选就能选 1 个,不选就能选 0 个。我们还是忽略不看,从它们的父亲结点开始考虑。
在以 6 为根的子树里面,如果不选 6 可以选 5 和 7 这 2 个,选 6 则只能选 1 个。
在以 2 为根的子树里面,选 2(2、5 和 7)或不选(1、5 和 7)都能选 3 个。
在以 3 为根的子树里面,选 3 (3、1、5 和 7)可以选 4 个,不选([1 或 2]、5 和 7)可以选 3 个。
整个问题的答案,以 4 为根的子树里面,选 4(4、[1 或 2]、5 和 7)可以选 4 个,不选(3、1、5 和 7)也可以选 4 个。
回想一下,求解的过程中,我们在分类讨论考虑的时候,影响决策的就是:如果选了这个根,那么它的儿子都不能选,于是选这个根的答案就是它的所有儿子不选的总和。如果不选这个根,它的儿子选不选都没问题,那么不选这个根的答案就是它的每个儿子选和不选中最大值的总和。
好了,现在我们知道,这其实就是一个1782 最大利润的简化版本,只不过所有点的权值为 1,其他几乎是一模一样的。
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 5e4 + 100;
int n;
vector <int> g[maxn];
int dp[maxn][5];
bool vis[maxn];
void dfs(int r) {
vis[r] = true;
dp[r][1] = 1;
dp[r][0] = 0;
for (int i = 0; i < g[r].size(); i++)
if (!vis[g[r][i]]) {
dfs(g[r][i]);
dp[r][0] += max(dp[g[r][i]][0], dp[g[r][i]][1]);
dp[r][1] += dp[g[r][i]][0];
}
}
int main(void) {
freopen("1784.in", "r", stdin);
freopen("1784.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
g[x].push_back(y); g[y].push_back(x);
}
memset(vis, false, sizeof vis);
dfs(1);
printf("%d\n", max(dp[1][0], dp[1][1]));
return 0;
}