概述
感觉还是非常巧妙地
光说理论不好讲,拿道题目来说P1273 有线电视网
这 道 题 很 难 想 这道题很难想 这道题很难想
但 是 如 果 把 每 棵 子 树 当 成 一 个 组 , 那 么 组 内 可 以 不 选 叶 子 节 点 但是如果把每棵子树当成一个组,那么组内可以不选叶子节点 但是如果把每棵子树当成一个组,那么组内可以不选叶子节点
选 1 个 叶 子 节 点 , 2 个 叶 子 节 点 . . . . . . . 选1个叶子节点,2个叶子节点....... 选1个叶子节点,2个叶子节点.......
而一个组中最多只能有一种决策,这不就是分组背包吗?
回 忆 一 下 普 通 的 分 组 背 包 转 移 color{Red}回忆一下普通的分组背包转移 回忆一下普通的分组背包转移
for(每一组物品)
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个叶子节点的最大收益
其中儿子代表每组物品,要选的叶子节点数是容量,当前儿子选几个叶子节点是这组要选哪些物品
然 后 的 话 把 背 包 容 量 倒 序 枚 举 可 以 优 化 掉 一 维 然后的话把背包容量倒序枚举可以优化掉一维 然后的话把背包容量倒序枚举可以优化掉一维
#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;
}
}
}
最后
以上就是笨笨果汁为你收集整理的树型分组背包(模板题)的全部内容,希望文章能够帮你解决树型分组背包(模板题)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复