浅谈泛化物品——树上背包优化
泛化物品
泛化物品,是一种没有固定费用(体积)和价值的物品。物品的价值,随着你给它定的费用(体积)而改变。
在
泛化物品的和与并
设:背包最大体积为
则有
我们称这种运算为泛化物品的和,泛化物品的和是把两个泛化物品和合并成一个泛化物品的运算,即枚举对这两个泛化物品如何分配体积。
对于具有树形依赖关系的背包问题,我们可以将每一棵子树当成一个泛化物品,这样对于每一个子树,子树的根节点与根节点相连的所有子树的泛化物品的和就是该子树的泛化物品。时间复杂度
如 [HAOI2010]软件安装
void dfs(int now){
for(int i=0;i<=m;i++){
if(new_w[now]<=i){
dp[now][i]=new_v[now];
}
else
dp[now][i]=-0x3f3f3f3f;
}
for(int i=new_head[now];i;i=new_edge[i].next){
int to=new_edge[i].to;
dfs(to);
for(int j=m;j>=new_w[now];j--){
for(int k=new_w[to];k<=j;k++){
dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[to][k]);
}
}
}
}
时间复杂度为 O(m^2)。
但是在经典问题
时间复杂度
很显然,进行泛化物品的并运算,比泛化物品的和运算,时间复杂度要更优。
所以我们要对树上背包问题进行优化,可以从把和运算转化成并运算入手
树上背包问题优化
对于一个根节点
void dfs(int now,int sum){//sum记录还剩多少容量
if(sum<=0)
return ;
for(int i=new_head[now];i;i=new_edge[i].next){
int to=new_edge[i].to;
for(int j=0;j<=sum-new_w[to];j++){//因为强制选了to,所以要给to留出空间
dp[to][j]=dp[now][j];//强制选择to,
}
dfs(to,sum-new_w[to]);//选了to 容量减少
for(int j=sum;j>=new_w[to];j--){
dp[now][j]=max(dp[now][j],dp[to][j-new_w[to]]+new_v[to]);//跟0/1背包统计答案的方法一样,两个泛化物品的并运算
}
}
}
时间复杂度
来源:2009年国家集训队论文集,浅谈背包问题