问题描述
有 N 个物品和一个容量是 V 的背包。
物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。
如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。
每件物品的编号是 i,体积是 vi,价值是 wi,依赖的父节点编号是 pi。物品的下标范围是 1…N。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,V,用空格隔开,分别表示物品个数和背包容量。
接下来有 N 行数据,每行数据表示一个物品。
第 i 行有三个整数 vi,wi,pi,用空格隔开,分别表示物品的体积、价值和依赖的物品编号。
如果 pi=−1,表示根节点。 数据保证所有物品构成一棵树。
输出格式
输出一个整数,表示最大价值。
数据范围
1≤N,V≤100
1≤vi,wi≤100
样例
输入样例
5 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
输出样例:
11
思路
用 F[root, m] 表示以 root 这个节点为根节点的子树消耗空间为m时的最大值, 递归遍历每一颗子树,第一次循环遍历物品,第二重循环遍历空间,第三重循环遍历决策
for(int i = h[x]; ~i; i= ne[i]){
int y = e[i];
dfs(y);
for(int j = m - v[x]; j >= 0; j--){
for(int k = 0; k <= j; k++){
f[x][j] = max(f[x][j], f[x][j - k] + f[y][k]);
}
}
}
因为要选择子树的节点必须选择父节点,故必须要给父节点留空间
for(int i = m; i >= v[x]; i--) f[x][i] = f[x][i - v[x]] + w[x];
如果空间不够选父节点,就不能选任何一个节点
for(int i = 0; i < v[x]; i++) f[x][i] = 0;
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 220;
int f[N][N], w[N], v[N];
int e[N], ne[N], h[N], len;
int n, m, root;
void add(int a, int b){
e[len] = b;
ne[len] = h[a];
h[a] = len++;
}
void dfs(int x){
for(int i = h[x]; ~i; i= ne[i]){
int y = e[i];
dfs(y);
for(int j = m - v[x]; j >= 0; j--){
for(int k = 0; k <= j; k++){
f[x][j] = max(f[x][j], f[x][j - k] + f[y][k]);
}
}
}
for(int i = m; i >= v[x]; i--) f[x][i] = f[x][i - v[x]] + w[x];
for(int i = 0; i < v[x]; i++) f[x][i] = 0;
}
int main(){
cin >> n >> m;
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i++){
int p;
cin >> v[i] >> w[i] >> p;
if(p == -1){
root = i;
}else add(p, i);
}
dfs(root);
cout << f[root][m] << endl;
return 0;
}