Codeforces 1153D 树形DP

题意:有一个游戏,规则如下:每个点有一个标号,为max或min, max是指这个点的值是所有子节点中值最大的那一个,min同理。问如何给这颗树的叶子节点赋值,可以让这棵树的根节点值最大。

思路:很明显的树形dp, 设dp[x]是指以x为根的子树中可以获得的最大的值, sz[x]是指以x为根的子树中叶子节点的个数。

若x是max, 那么dp[x] = max(sz[x] - sz[y] + dp[y]),对应的决策相当于把最大的几个值给dp[y] - sz[y]最大的那颗子树。

若x是min, 首先需要统计每颗子树的sz[y] - dp[y], 这些都不可能被选上了,之后,还要统计有多少棵子树(假设有z棵), 其中z - 1个肯定选不上了,所以答案是sz[x] - Σ(sz[y] - dp[y]) - (z - 1)。

这两条对照这样例的图很容易就能发现了,然而昨晚思路跑偏了,这题都没做出来,含泪掉分。。。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 300010;
vector<int> G[maxn];
int sz[maxn], dp[maxn], a[maxn];
void dfs(int x) {
	dp[x] = 1;
	if(G[x].size() == 0) {
		sz[x] = 1;
		return; 
	}
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i];
		dfs(y);
		sz[x] += sz[y];
	}
	if(a[x] == 1) {
		for (int i = 0; i < G[x].size(); i++) {
			int y = G[x][i];
			dp[x] = max(dp[x], sz[x] - sz[y] + dp[y]);
		}
	} else {
		int tmp = 0;
		for (int i = 0; i < G[x].size(); i++) {
			int y = G[x][i];
			tmp += sz[y] - dp[y];
		}
		dp[x] = sz[x] - tmp - G[x].size() + 1;
	}
}
int main() {
	int n, x;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	for (int i = 2; i <= n; i++) {
		scanf("%d", &x);
		G[x].push_back(i);
	}
	dfs(1);
	printf("%d
", dp[1]);
} 

  

原文地址:https://www.cnblogs.com/pkgunboat/p/10704633.html