洛谷2P2014 [CTSC1997] 选课 有依赖的背包/树上背包
题目链接:https://www.luogu.com.cn/problem/P2014
首先这题我们可以看成一个包含 \(n+1\) 个点(还有一个点是 \(0\) 号点,且定义 \(s_0 = 0\))。
每个节点 \(i\) 可以看成一个费用为 \(1\),价值为 \(s_i\) 的物品。
定义状态 \(f_u,i\) 表示在以 \(u\) 为根的子树中选择恰好 \(i\) 个点的最大总价值。
则状态转移方程为:
\[f_{u, i} = \max\limits_{ v \in son_u }(f_{u, i}, f_{u, i-j} + f_{v, j})
\]
最终的答案为 \(f_{0, m+1}\)(因为算上节点 \(0\),但其实节点 \(0\) 并没有造成贡献,因为 \(s_0 = 0\))
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 305;
int n, m, s[maxn], f[maxn][maxn], sz[maxn];
vector<int> g[maxn];
void dfs(int u, int p) {
sz[u] = 1;
for (auto v : g[u])
if (v != p)
dfs(v, u), sz[u] += sz[v];
f[u][1] = s[u];
for (auto v : g[u])
for (int i = sz[u]; i >= 2; i--)
for (int j = 1; j <= min(sz[v], i-1); j++)
f[u][i] = max(f[u][i], f[u][i-j] + f[v][j]);
}
int main() {
cin >> n >> m;
for (int i = 1, k; i <= n; i++) {
cin >> k >> s[i];
g[k].push_back(i);
}
dfs(0, -1);
// 0也算一件价值为0的物品,所以一共m+1件物品
cout << f[0][m+1] << endl;
return 0;
}