You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

61 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n; // 物品个数
int m; // 背包容量
int v[N]; // 物品的体积
int w[N]; // 物品的价值
int p; // 依赖的物品编号
int root; // 根节点
// 多叉树转二叉树
int l[N], r[N]; // 左儿子,右兄弟
int son[N]; // 记录i的目前输入的最后一个儿子是谁为了后面再有其它儿子加入时放到最后一个儿子的右子树上
/*i表示结点j表示体积
f[i][j]表示i及其兄弟结点组合不超过体积j的最大价值。由于根结点没有兄弟结点故f[root][v]
表示体积不超过v的最大价值
黄海注这个状态表示很有意思网上有的人说是以i为根的子树在体积不超过j情况下的最大价值这样的说法是错误的
*/
int f[N][N];
int dfs(int i, int j) {
if (i == 0 || j == 0) return 0; // 递归出口,i=0:比如一个结点没有左儿子默认就是i=0;
if (f[i][j]) return f[i][j]; // 记忆化
// ① 不要i节点为根的子树最大价值从右子树中来,右子树就是右侧所有兄弟节点中来 (不理解时看一眼题解中的图就明白了)
f[i][j] = dfs(r[i], j);
// ② 计算以自己为根的子树最大值(需要预留出w[i]的空间出来)
for (int k = 0; k <= j - w[i]; k++) // 遍历所有可能的空间
// 如果要了i结点那么结果可能来自三方面左子树右子树自己的v[i]
f[i][j] = max(f[i][j], dfs(r[i], k) + dfs(l[i], j - w[i] - k) + v[i]);
// 返回max
return f[i][j];
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
// 体积,价值,依赖的物品编号
cin >> w[i] >> v[i] >> p;
// 将录入的多叉树转为二叉树,方便查找
if (p == -1)
root = i; // 记录根节点
else {
if (son[p] == 0) l[p] = i; // p还没有录入过儿子那么记录p的左儿子=i
// 如果p录入过儿子那么需要找出它最后一个儿子是son[p],
// 将i记录到最后一个儿子的右结点上r[son[p]]=i
else
r[son[p]] = i;
son[p] = i; // 修改p的最后一个儿子为i
}
}
// 搜索
printf("%d\n", dfs(root, m));
return 0;
}