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.
|
|
|
|
#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;
|
|
|
|
|
}
|