选取 个结点
这是最普遍的情况, 从树中选取
符合直觉地, 设
其中
其最优性和可行性都是显然的, 我们考虑这个算法的复杂度. 看起来似乎是
选取结点的代价之和至多为
在这个问题中为每个结点引入了代价, 此时上述的复杂度分析不再适用.
我们不妨考虑换一种思路, 正常的
设
- 若选该物品, 则可以选择它子树中的物品,
. - 若不选该物品, 则它子树内的物品都不可以选, 而子树中的编号恰好是连续的, 于是
.
这样转移时间复杂度即为
int n, m, dfn;
std::vector<std::vector<int>> E, f;
std::vector<int> w, v, siz;
void dfs (int u) {
for (int v : E[u]) dfs(v), siz[u] += siz[v];
dfn++;
for (int j = 0; j <= m; j++) {
f[dfn][j] = f[dfn - siz[u]][j];
if (j >= w[u]) f[dfn][j] = std::max(f[dfn][j], f[dfn - 1][j - w[u]] + v[u]);
}
}
int knapsack_on_tree () {
siz = std::vector<int>(n + 1, 1);
f = std::vector<std::vector<int>>(n + 2, std::vector<int>(m + 1));
dfs(0);
return f[n + 1][m];
}
v1.3.10