Appearance
简介
树形 DP 以树形结构为研究对象。通常设
例 1
给定一棵
分析
计算顺序为
cpp
// son[u] : 节点 u 的子节点集合
vector<int> son[];
// 求以 u 为根的子树中节点个数
void dfs(int u) {
f[u] = 1;
for (int v : son[u]) {
// 先计算子节点
dfs(v);
f[u] += f[v];
}
}
例 2
公司有
每个人都有⼀个欢乐值,给出公司所有人的上下级关系,求一个邀请方案,使欢乐值的和最大。
分析
- 若
号员工参会,他的直接下属都不来:
- 若
号员工参会,他的直接下属爱来不来,于是取最大值:
时间复杂度为
cpp
vector<int> son[];
// 求出 u 号员工对应的 f[u][0] 和 f[u][1]
void dfs(int u) {
f[u][1] = h[u];
for (int v : son[u]) {
// 先计算子节点
dfs(v);
f[u][1] += f[v][0];
f[u][0] += max(f[v][0], f[v][1]);
}
}
例 3:树形 DP + 背包 DP
有
分析
将每门课程看作树中的节点,
为了方便解决问题,新增
执行
- 将
个节点分成两组,一组 个,另一组 个; - 将第一组
个节点放在以 为根节点的子树中,最大学分为 ; - 将第二组
个节点放在以 为根节点的子树中,但不放在以 为根节点的子树中,最大学分为 。
在主程序中执行
边界条件为
问题的解是
cpp
void dfs(int u) {
f[u][1] = s[u];
for (int v : son[u]) {
dfs(v);
for (int j = m; j >= 1; j --)
for (int k = j - 1; k > 0; k --)
f[u][j] = max(f[u][j], f[v][k] + f[u][j - k]);
}
}