背包dp,背包到底是什么?
7.有依赖的背包问题
有依赖的背包问题指的是如果物品j依赖于物品i, 要想选择物品j必须先选择了物品i.
一个简化的问题是:一件物品只会依赖最多一件物品,且附属品不会被依赖.
思考
首先想一下我的dp训练第19题黄金矿工.那道题里实际上一条过原点的直线上的金块会按顺序依赖.当时的解法是将一条线上的所有物品看成一组,然后将组中前方物品的值加在后方物品上.这种方法在解决链状依赖时非常有效.
如果不是链状依赖呢?比如物品2和3都依赖于物品1,这时总的情况实际上有5种:都不选,只选1,选12,选13,选123.物品有多件时情况数会成指数增长,显然枚举是不可行的.
简化后的问题
背包九讲原文中给出的方法是处理这一组物品,对每个费用只保留价值最大的情况.相当于做成了一个泛化物品(泛化物品是指某种物品给定一个费用就会返回一个价值).然后使用第六讲分组背包中的算法就可以解决.
关键的问题是怎么处理?此时一组物品中有1个主件和若干个附件,在选择主件后,每个附件都是可选可不选的,现在需要得到每个特定费用的最大价值,怎么做?
答案是,01背包. 对所有附件做一次01背包之后,再加上主件的花费和价值,就得到了这个泛化物品的所有属性.
4约17日补 算法
只空谈算法而不写程序是ACMer大忌!我怎么把这个忘了!
一个标准的解法是对于每个主件从dp数组copy一个tmp数组,然后让所有这个主件的附件对tmp数组做01背包.做完之后对每个值加上主件的体积和价值,求一个max.
for(int i=1;i<=n;i++)
{
memcpy(tmp,dp,sizeof(dp));
for(each attachment k of item i)
for(int j=v;j>=volume[k];j--)
tmp[j]=max(tmp[j],tmp[j-volume[k]]+value[k]);
for(int j=v;j>=volume[i];j--)
dp[j]=max(dp[j],tmp[j-volume[i]]+value[i]);
}
对每个附件做完01背包之后,tmp表示前i-1组物品和这些附件在每个体积时的最优情况.但是,如果需要tmp里的某个值,得先经过主件之后才能转移到dp中.
从dp和tmp得到dp的过程实际上也是一个01背包,只是通常的01背包是针对数组本身选或不选,而本处则是针对两个数组谁可以转移到新的dp做出的选择.
按最优状态分析一下,新的dp[j]只可能会由两个状态转移而来,一个是这一组物品任意一个都不选,即旧dp[j],另一个则是选了主件和某些附件,则由tmp转移.
这里还是很绕,多回来看一看.
更复杂的问题
复杂问题是指,主件和附件之间的依赖关变成了一棵树,所有依赖的集合是一个森林.这里假设每个物品只能依赖一件物品且不会循环依赖.
解法是,从叶子到根依次进行上述的01背包过程,就得到了这整棵树的泛化模型,森林中所有树的泛化模型都得到后,使用分组背包的算法即可解决问题.
8.泛化物品
泛化物品准确来说,不是一类题目,而是一种思想.泛化物品的定义是
考虑这样一种物品,它并没有固定的费用和价值,而是它的价值随着你分
配给它的费用而变化。这就是泛化物品的概念。
或者
更严格的定义之。在背包容量为V 的背包问题中,泛化物品是一个定义
域为0 . . . V 中的整数的函数h,当分配给它的费用为v时,能得到的价值就
是h(v)。
再或者
这个定义有一点点抽象,另一种理解是一个泛化物品就是一个数组h[0 . . . V ],
给它费用v,可得到价值h[v]。
当我看到这里的时候,我真正觉得这个概念的提出者和背包九讲的作者崔添翼是一个了不起的人物.他用这样的概念,简单准确的描述了到底什么是背包,背包问题到底在干什么.
一个01背包中的物品(体积ci,价值wi),它的泛化物品模型是h(ci)=wi,h(其他)=0.
一个完全背包中的物品,它的模型是h(ci*k)=wi*k,其中k为正整数且ci*k<=V, h(其他)=0.
一个多重背包中的物品,则是h(ci*k)=wi*k,其中k<=ni且ci*k<=V, h(其他)=0.
一个互斥的物品组,h(ci)=wi,i取遍组中物品的编号,ci相同时wi取最小值,h(其他)=0
泛化物品的和
如果给定两个泛化物品a和b,现在有体积v来装这两种物品,要求获得最大价值.怎么做?
上文中有提到,将泛化物品直接使用分组背包的方法可以求解,注意泛化后每一组中互斥物品个数实际上都是v了,复杂度O(n*v*v),其中n为泛化物品个数.
如果仅仅有两个物品呢,设用体积j来装这两种物品的最大价值为dp[j]
则dp[j]=max{a(k)+b(v-k)},k取遍0到j,答案就是dp[v]
新合成的dp数组,实际上,也是一个泛化物品.
由泛化物品的性质可知,如果将两个泛化物品这样合成一个新的物品,新的物品在问题中完全可以取代原有的两个物品.
背包与泛化物品
背包问题中都会有的dp数组,处理完之后的值实际上也是一个泛化物品,是所有原有物品的和.
所以,求解背包实际上就是求得各个体积时的最优价值,得到最终的泛化物品.
带着泛化物品的思想,可以再去回头看看第六和第七讲.
其他
还有一些想总结的东西,比如背包问题到底是什么?
等学完第九讲后一起总结.
习题
见后文