洛谷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;
}
posted @ 2025-04-28 19:42  quanjun  阅读(9)  评论(0)    收藏  举报