DP--背包九讲学习笔记

一、01背包

(1)空间优化——一维数组

以前不明白为什么这里需要用倒序来推导,现在看明白了。

因为在每一次主循环开始时,dp数组存贮着的就是i-1的状态。

而如果是顺序的,那么假如当前更新到了dp[j],此时的dp[j-c[i]]是已经在本轮中更新过了的,相当于是dp[i][j-c[i]]而不是dp[i-1][j-c[i]]。

这张截图也说得很清楚了。

DP--背包九讲学习笔记_第1张图片

(2)时间小优化——

第二层循环只进行到cost

DP--背包九讲学习笔记_第2张图片


(3)初始化的细节——

由两种不同的提问方式来区分

如果是“要求恰好装满”,那么则要使dp[0]=0,而dp[1...W]=-inf.

如果是“不要求恰好装满”,那么dp{0...W]=0.


这是我自己的解释:

因为我们只用一个数组,那么dp初始化的值在将来什么时候用都不确定。

如果是“恰好装满”,那么每个dp的含义都应该是是代表已经装了j重量的物品后可以获得的最大价值。

那么当前任一个dp[j](j!=0)值都不可能是零,因为它里面必须装有东西!!!

除非存在价值为零的商品,且所有其他商品的价值都比零小,而这种题目一般不会出现吧。

如果是“非恰好装满”,那么每个dp的含义应该是代表容量大小为j的背包可以获得的最大价值。

而这个时候,dp[j]为零就是合法的。

DP--背包九讲学习笔记_第3张图片


(4)一个常数优化

前面的伪代码中有for v=V..1,可以将这个循环的下限进行改进。
由于只需要最后f[V]的值,倒推前一个物品,其实只要知道f[V-w[n]]即可。以此类推,对以
第j个背包,其实只需要知道到f[V-(后n-j个物品的重量总和)]即可,即代码中的

DP--背包九讲学习笔记_第4张图片

DP--背包九讲学习笔记_第5张图片


二、完全背包:

(1)最最基础的思路:


(2)但是上面这个时间复杂度太高,可以加一个优化,


(3)接下来是一种更为简单有效的办法。

我们惯常是以+1来枚举的。但是对于某当前的剩余容量V,和当前的物品,

我们最多可以拿V/c[i] 个,而这个数我们可以用二进制来表示,也就是说我们

只需要确定重量为1c[i],2c[i] ,3c[i] ,4c[i] ...的商品拿一件还是不拿就可以了

这样我们就回归到了01背包的问题之中。

那么复杂度就是O{N·V·logV/c[i]}

DP--背包九讲学习笔记_第6张图片


(4)但是上面的始终是三层循环,实际上我们有O{N·V}的算法。

DP--背包九讲学习笔记_第7张图片

我自己的理解是,对于每一个状态dp[j](不管是当前i还是上一个循环的i-1)我们都可以选择“维持当前状态不拿商品”,也可以“拿商品”。在下一个状态dp[j+c[i]]也是同样操作。这样一来就是实现了从一种物品一个不拿到一个物品拿多个的各种情况的最优化选择。


三、多重背包:

多重背包就是将完全背包每个物品的个数从无限变为了不一定相同的有限个。
总的来说,多重背包思路基本和完全背包一致,也可以使用二进制数优化至O{N·SEGMA(logV/c[i])}
但是如果想要做到O{N·V}的复杂度则需要用到单调队列的优化。
这里贴一个单调队列优化的博客:
点击打开链接

这里顺便解释一下,它里面是这么说的

记住!只有形如 dp[i]=max/min (f[k]) + g[i]  (k

优化的对象就是f[k]。

说一下我的理解:
不管dp方程式是几维,只要形如 dp[i]=max/min (f[k]) + g[i]  其中f[k]是更内层的循环的变量即可。 



















你可能感兴趣的:(算法学习笔记,算法学习笔记)