参考:分组背包代码
for(int i=1;i<=n;i++)//遍历每个组
for(int j=V;j>=0;j--)
for(int k=1;k<=s[i];k++)//遍历这个组中的元素,把选它纳入考虑
if(j-v[i][k]>=0)dp[j]=max(dp[j],dp[j-v[i][k]]+w[i][k]);
AC代码+详细注释
#include<bits/stdc++.h>
using namespace std;
const int M=105;
int dp[M][M],v[M],w[M],fa[M],m;
vector<int> chi[M];//每一个节点的儿子
void dfs(int x){
//如果要选择以x为根的子树里的节点,则必须选x
//每一个dp[x][j](j>=v[x])都有一个初始的可行方案:只选x
for(int j=v[x];j<=m;j++)dp[x][j]=w[x];
//y : x的儿子节点
//每次都可以在以y为根的子树中选择几个节点
//这几个节点一共消耗k的体积,总价值为dp[y][k]
//相当于分组背包
//一个以y为根的子树是一个组,从一个组中选一个物品,它的体积是k,价值是dp[y][k]
for(int i=0;i<chi[x].size();i++){
int y=chi[x][i];
dfs(y);
for(int j=m;j>=v[x];j--){//保证下面的dp[x][j-k]是以前的
for(int k=v[y];k<=min(j-v[x],m);k++){//j-k>=v[i],留出x的空间
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]);
}
}
}
}
int main(){
int n,root;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&v[i],&w[i],&fa[i]);
chi[fa[i]].push_back(i);
if(fa[i]==-1)root=i;
}
dfs(root);
printf("%d",dp[root][m]);
return 0;
}