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.

57 lines
2.0 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 = 310;
int n, m;
int w[N];
int f[N][N];
//创建邻接表
int h[N], e[N], ne[N], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
//分组背包过程
void dfs(int u) {
for (int i = h[u]; i != -1; i = ne[i]) {//物品组
dfs(e[i]);
for (int j = m - 1; j >= 0; j--) //体积
for (int k = 0; k <= j; k++) //决策
f[u][j] = max(f[u][j], f[u][j - k] + f[e[i]][k]);
}
//把老大加上去,同样由于滚动数组对于自己本行的依赖,所以采用了倒序
//给老大预留了一个位置1,所以i>=1
for (int i = m; i >= 1; i--) f[u][i] = f[u][i - 1] + w[u];
//要注意0这个边界当当前节点的选课数量为0时是没有意义的所以需要初始化为0但是其本身就是0
//所以这里直接不循环即可,类比一下10_2.cpp
//f[u][0]=0;
}
int main() {
/**
树形DP+01背包-->映射成分组背包
如果有三个子树表示有三个物品组每个物品组中有m+1(0~m)个物品
第k个物品的体积是k,价值:f(s1,k)
第一层:物品组,第二层:从大到小循环体积,第三层:决策
时间复杂度O(n*m^2)
但是这道题可能不只有一个点没有父结点而是有好多点都可能没有父结点这时我们可以把0看成虚拟的根结点最终我们取f[0,m+1]即可
同时因为每选一门课都需要添加上0这个结点所以最终是m+1
*/
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i++) {
int p;
cin >> p >> w[i];
//添加虚拟根的技巧
add(p, i);//若不存在先修课则该项为0:这为我们创建虚拟根0号结点创造了条件
}
//所有方案都需要添加虚拟根结点0就相当于选了m+1门课
m++;
dfs(0);
cout << f[0][m] << endl;//由于m已经++所以这里就是f[0][m]了
return 0;
}