感觉还是非常巧妙地
光说理论不好讲,拿道题目来说P1273 有线电视网
这 道 题 很 难 想 这道题很难想 这道题很难想
但 是 如 果 把 每 棵 子 树 当 成 一 个 组 , 那 么 组 内 可 以 不 选 叶 子 节 点 但是如果把每棵子树当成一个组,那么组内可以不选叶子节点 但是如果把每棵子树当成一个组,那么组内可以不选叶子节点
选 1 个 叶 子 节 点 , 2 个 叶 子 节 点 . . . . . . . 选1个叶子节点,2个叶子节点....... 选1个叶子节点,2个叶子节点.......
而一个组中最多只能有一种决策,这不就是分组背包吗?
回 忆 一 下 普 通 的 分 组 背 包 转 移 color{Red}回忆一下普通的分组背包转移 回忆一下普通的分组背包转移
1
2
3
4
5for(每一组物品) for(背包的容量) for(当前这组选哪些物品) 开始dp
那 我 们 效 仿 这 个 , 定 义 状 态 d p [ i ] [ u ] [ j ] 的 含 义 为 那我们效仿这个,定义状态dp[i][u][j]的含义为 那我们效仿这个,定义状态dp[i][u][j]的含义为
在 u 为 根 的 子 树 中 , 在 前 i 个 儿 子 中 选 择 j 个 叶 子 节 点 的 最 大 收 益 在u为根的子树中,在前i个儿子中选择j个叶子节点的最大收益 在u为根的子树中,在前i个儿子中选择j个叶子节点的最大收益
其中儿子代表每组物品,要选的叶子节点数是容量,当前儿子选几个叶子节点是这组要选哪些物品
然 后 的 话 把 背 包 容 量 倒 序 枚 举 可 以 优 化 掉 一 维 然后的话把背包容量倒序枚举可以优化掉一维 然后的话把背包容量倒序枚举可以优化掉一维
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#include <bits/stdc++.h> using namespace std; const int maxn=3009; int n,m,dp[maxn][maxn],w[maxn]; struct p{ int to,nxt,w; }d[maxn]; int head[maxn],cnt=1; void add(int u,int v,int w){ d[cnt]=(p){ v,head[u],w},head[u]=cnt++; } int dfs(int u) { dp[u][0]=0; if( u>n-m ) { dp[u][1]=w[u]; return 1; } int leaf=0; for(int i=head[u];i;i=d[i].nxt) { int v=d[i].to; int t=dfs(v); leaf+=t; for(int j=leaf;j>0;j--)//一共选几个叶子节点 { for(int q=0;q<=j&&q<=t;q++) dp[u][j]=max(dp[u][j],dp[v][q]+dp[u][j-q]-d[i].w); } } return leaf; } int main() { cin >> n >> m; for(int i=1;i<=n-m;i++) { int s; cin >> s; for(int j=1;j<=s;j++) { int r,w; cin >> r >> w; add(i,r,w); } } for(int i=0;i<=3000;i++) for(int j=0;j<=3000;j++) dp[i][j]=-999999999; for(int i=n-m+1;i<=n;i++) cin >> w[i]; dfs(1); for(int j=m;j>=0;j--) { if(dp[1][j]>=0) { cout<<j; return 0; } } }
最后
以上就是笨笨果汁最近收集整理的关于树型分组背包(模板题)的全部内容,更多相关树型分组背包(模板题)内容请搜索靠谱客的其他文章。
发表评论 取消回复