《DP学习系列》从零开始学习动态规划,有依赖的背包问题(七)

1. 预备部分

  如果真的从零开始学习DP,那么从七讲以后的部分就要烧脑细胞了。如果是为了笔试准备,笔者感觉后面就可以不用看了。但是笔者这里还是完整记录完,我们看别人的结论尚且要思索万千,所以崔添翼真是非常聪明。该部分来自NOIP2006的比赛原题,所以我们初学者也有必要看看前因后果,原题如该博主记录所示

2. 简化的问题

  金明的预算的原题节选:

把想买的物品分为两类:主件与附件,附件是从属于某个主件的,如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。

  背包九讲泛化该问题,抓住了问题的本质。

这种背包问题的物品间存在某种“依赖”的关系。也就是说,物品i依赖于 物品j,表示若选物品i,则必须选物品j。为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。

3. 算法

按照背包问题的一般思路,仅考虑一个主件和它的附件集合。可是,可用的策略非常多,包括:一个也不选,仅选择主件,选择主件后再选择一个附件,选择主件后再选择两个附件……无法用状态转移方程来表示如此多的策略。事实上,设有n个附件,则策略有2^n + 1个,为指数级。

  崔作者说没有办法写出来,我觉得读者也应该确实尝试去写,就知道为什么需要下面的优化了。因为太多,没有办法表示,所以崔思考了这些不同的选择之间的关系:

  • 考虑到所有这些策略都是互斥的(也就是说,你只能选择一种策略),所以一个主件和它的附件集合实际上对应于6中的一个物品组,每个选择了主件又选择了若干个附件的策略对应于这个物品组中的一个物品,其费用和价值都是这个策略中的物品的值的和。但仅仅是这一步转化并不能给出一个好的算法,因为物品组中的物品还是像原问题的策略一样多。
  • 再考虑对每组内的物品应用2.3中的优化。我们可以想到,对于第k个物品组中的物品,所有费用相同的物品只留一个价值最大的,不影响结果。所以,可以对主件k的“附件集合”先进行一次01背包,得到费用依次为0…V − Ck所有这些值时相应的最大价值Fk[0 …. V − Ck]。那么,这个主件及它的附件集合相当于V − Ck + 1个物品的物品组,其中费用为v的物品的价值为Fk[v − Ck] +Wk, v的取值范围是Ck ≤ v ≤ V 。

  最难理解的就是第二点,但是第二点又是本文的核心。可以再想想我们需要优化下之前每组的太多的策略的缺陷,但是如何优化呢?值得注意的是,崔说这种优化等同于2.3的输入提前优化,指的是01背包方式问题的输入提前优化。
  说白了,因为每个附件都可以选或者不选,所以第k组中选择了多少的附件的问题转化为01背包问题,而且我们可以对附件进行提前优化,改善时间复杂度。再次捋顺逻辑,首先因为依赖关系,可以将一些物品绑定(分)成一个组,然后每组中的物品选择策略可以分成一个都不选和选择主件及L个附件的问题,之后选择L个附件的问题又可以转化为01背包问题。原文没有直接给出伪代码,根据上面的分析,我们也能写出来这伪代码:

//总问题
F[0...V]
F[0]=0

for k=1 to K
    for v=V to 0
        for i=0 to V-Ck
            F[v]=max{F[v],F[v-Ck-i]+Y[i]+Wk}
//子问题
Y[0...V-Ci]
Y[0]=0

for j=0 to J
    for v=V-Ck to Cj
        Y[v]=max{Y[v],Y[v-Ck-Cj]+Wj} 

  自己写出来伪代码时,思路就很清晰了,可以选择在子问题中进行输入优化。以上伪代码没有做该优化,所以本质上我们将子问题单独处理,优化了每组的选择策略数量。

4. 再提高难度

  • 更一般的问题是:依赖关系以图论中“森林” 3的形式给出。也就是说,主件的附件仍然可以具有自己的附件集合。限制只是每个物品最多只依赖于一个物品(只有一个主件)且不出现循环依赖。
  • 解决这个问题仍然可以用将每个主件及其附件集合转化为物品组的方式。唯一不同的是,由于附件可能还有附件,就不能将每个附件都看作一个一般的01背包中的物品了。若这个附件也有附件集合,则它必定要被先转化为物品组,然后用分组的背包问题解出主件及其附件集合所对应的附件组中各个费用的附件所对应的价值。
  • 事实上,这是一种树形动态规划,其特点是,在用动态规划求每个父节点的属性 之前,需要对它的各个儿子的属性进行一次动态规划式的求值。这已经触及到了“泛化物品”的思想。看完8后,你会发现这个“依赖关系树”每一个子树都等价于一件泛化物品,求某节点为根的子树对应的泛化物品相当于求其所有儿子的对应的泛化物品之和。

  第三点的总结以后再回顾,现在用图形表示的上面的解决逻辑:
这里写图片描述

5. 总结

  背包九讲还有两讲就完了,之后笔者考虑直接根据DSAA的章节学习吧,算法导论的计划暂时修改下,因为时间紧凑,Leetcode分成三阶段,总数目在300题吧。

猜你喜欢

转载自blog.csdn.net/LoveStackover/article/details/80652494