树形背包:必须选择父亲节点才能选择其子节点,求一定体积下的最大点权和
模板题:P2014 [CTSC1997]选课
O
(
n
w
2
)
O(nw^2)
O(nw2) 算法:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示以
i
i
i 为根的子树,体积为
j
j
j 的最大值
在
d
f
s
dfs
dfs 里枚举所有子树的状态即可
注意:若每个点的体积都为 1 1 1 ,选择枚举所有子树的大小,复杂度为 O ( n w ) O(nw) O(nw)
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 305;
int n, m, k[maxn], s[maxn];
int dp[maxn][maxn];
vector <int> g[maxn];
void dfs(int u){
dp[u][1] = s[u];
for(auto v : g[u]){
dfs(v);
for(int j=m+1; j; j--)
for(int k=0; k<j; k++)
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
}
}
signed main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) {
scanf("%d%d", k+i, s+i);
g[k[i]].push_back(i);
}
dfs(0);
printf("%d\n", dp[0][m+1]);
}
O
(
n
w
)
O(nw)
O(nw) 算法:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示
d
f
s
dfs
dfs序下为编号
i
i
i 的结点,体积为
j
j
j 的最大值
若选当前节点,直接更新即可
若不选当前节点,则更新下一颗子树
则预处理
d
f
s
dfs
dfs 序 与 每个节点的下一颗子树的
d
f
s
dfs
dfs 序号
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 305;
int n, m, k[maxn], s[maxn];
int dp[maxn][maxn], v[maxn];
int dfn[maxn], tot, nxt[maxn];
vector <int> g[maxn];
void dfs(int u){
dfn[u] = tot++;
for(auto v : g[u]) dfs(v);
nxt[dfn[u]] = tot;
}
signed main() {
scanf("%d%d", &n, &m); m++;
for(int i=1; i<=n; i++) {
scanf("%d%d", k+i, s+i);
g[k[i]].push_back(i);
}
dfs(0);
memset(dp, 128, sizeof(dp));
memset(dp[0], 0, sizeof(dp[0]));
for(int i=1; i<=n; i++) v[dfn[i]] = s[i];
for(int i=0; i<=n; i++)
for(int j=0; j<=min(i, m); j++){
dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j] + v[i]);
dp[nxt[i]][j] = max(dp[nxt[i]][j], dp[i][j]);
}
printf("%d\n", dp[n+1][m]);
}