Files
python/TangDou/AcWing/286.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

57 lines
2.0 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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