树形dp
树形dp
树形dp,即在树上进行的 dp。由于树固有的递归性质,树形dp 一般都是递归进行的。
例题1(洛谷 P1352 没有上司的舞会)
我以这道题为例,给大家介绍一下树形dp 的一般过程。
我们发现这道题跟每一个人去不去有很大关系。所以我们用 \(f(i,0/1)\) 表示到第 \(i\) 个人(去为 \(1\),不去为 \(0\))最大的快乐指数。于是我们可以求出每一个 \(f(i,0/1)\)。
对于每一个状态(\(0\) 或 \(1\)),我们可以按下面的方法处理。
- 上司不参加舞会,则下属可参加可不参加,所以 \(f(i,0)=\sum\max\{f(x,0),f(x,1)\}\)。
- 上司参加舞会,则下属一定不能参加舞会,所以 \(f(i,1)=\sum f(x,0)+r_i\)。
分析完后可以发现,我们可以用 \(dfs\),每次计算完 \(f(x,0)\) 和 \(f(x,1)\) 后,立刻加入 \(f(i,0)\) 和 \(f(i,1)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 6010;
int r[kMaxN], in[kMaxN], f[kMaxN][2], n, root;
vector<int> e[kMaxN];
void dfs(int x) {
if (!e[x].size()) {
f[x][1] = r[x];
return;
}
for (auto i : e[x]) {
dfs(i);
f[x][0] += max(f[i][0], f[i][1]), f[x][1] += f[i][0];
}
f[x][1] += r[x];
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> r[i];
}
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v, e[v].push_back(u), in[u]++;
}
for (int i = 1; i <= n; i++) {
(!in[i]) && (root = i);
}
dfs(root);
cout << max(f[root][0], f[root][1]) << '\n';
return 0;
}