这是树形DP,一般我们就从叶子节点开始往上找,用子节点更新父亲节点
我们定义一个f[i][j] 表示 以i为根的子树 用掉j的空间 所获得的最大价值
初始化要注意,0 < j < m时并不是所有的f都为0,
因为不选就整颗子树就都不能选了,
所以计算前只有f[i][0] = 0 , f[i][w[i]] = v[i];
其他的都置为无穷小就行了
然后我们还需要一个g[i][j]来表示 当前这个根节点的到第i个儿子时,用j的空间所获得的最大价值
然后在遍历子节点的时候更新一下g数组
具体就是g[i][j] = g[i - 1][j - k] + f[y][k] (y是第i个儿子的编号)
处理完g数组以后,就能用子节点来更新父节点了
f[u][j] = g[r][j - w[u]] + v[u];
减去w[u]是因为选这颗子树就必须选这个点
代码如下
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int N = 200;
const int INF = -1e9;
int n,m;
int w[N];
int v[N];
int f[N][N];//f[i][j] 以i为根的子树 用掉j的空间 所获得的最大价值
vector <int> map[N];
void dfs(int u)
{
int g[N][N];//g[i][j] 第i个儿子 用掉j的空间 所获得的的最大价值
memset(g,INF,sizeof g);
int r = map[u].size() - 1;
for(int i = 0 ;i < map[u].size();i ++)
{
int y = map[u][i];
dfs(y);
for(int j = 0;j <= m;j ++)
{
g[i][j] = g[i - 1][j];
for(int k = 0;k <= j;k ++)
g[i][j] = max(g[i][j],g[i - 1][j - k] + f[y][k]);
}
}
f[u][0] = 0;
f[u][w[u]] = v[u];
for(int j = w[u];j <= m;j ++)
{
f[u][j] = max(f[u][j],g[r][j - w[u]] + v[u]);
}
}
int main()
{
cin >> n >> m;
memset(f,INF,sizeof f);
int s;//(记录根节点是哪一个)
for(int i = 1;i <= n;i ++)
{
int k;
cin >> w[i] >> v[i] >> k;
if(k == -1) s = i;
else map[k].push_back(i);
}
dfs(s);
cout << f[s][m];
return 0;
}
tql
tql,但有些人是无法超越的