写在背包问题之前,我想说一下对循环顺序的理解。背包问题都会有备选集
ϕ
~\phi~
ϕ 和限制数
N
~N~
N ,
ϕ
~\phi~
ϕ 是一个列表,
N
~N~
N 是一个整数。循环顺序一般都是先关于备选集,再是关于限制数,解释为在
ϕ
k
=
[
1
,
.
.
.
,
k
]
,
k
≤
N
~\phi_k=[1,...,k],k\leq N~
ϕk=[1,...,k],k≤N ,
q
∈
[
1
,
.
.
.
,
N
]
~q \in[1,...,N]~
q∈[1,...,N] 的条件下
f
(
q
,
ϕ
k
)
~f(q,\phi_k)~
f(q,ϕk) 的值,然后将
ϕ
k
~\phi_k~
ϕk 扩大成
ϕ
k
+
1
~\phi_{k+1}~
ϕk+1 ,求
f
(
ϕ
k
+
1
,
q
)
~f(\phi_{k+1},q)~
f(ϕk+1,q) 的值,最后一直到求出
f
(
ϕ
,
q
)
~f(\phi,q)~
f(ϕ,q) 的所有值,返回
f
(
ϕ
,
N
)
~f(\phi,N)~
f(ϕ,N) 即可。
01背包问题
01背包问题是经典的动态规划思想的一类问题,题目内容是有一个固定载重为
W
W
W的背包,另有
n
n
n种物品,每件物品具有两个属性,分别重量
w
i
w_i
wi和价值
v
i
v_i
vi。要求每种物品只能选择一次或者不选,问在不超过载重
W
W
W的情况下,装的物品的总价值最大为多少?
分析问题:这里假定大家已经知道了这题的思路是动态规划!!!从上面的题目中可以看出,01问题就是就是“选”与“不选”的问题。即主要判断在满足载重限制的条件下,物品
i
~i~
i 选择之后背包的总价值分析。
设dp[
i
i
i][
j
j
j]表示前
i
~i~
i 件物品在载重为
j
~j~
j 的背包中的最大价值,下面来分析每个dp[
i
i
i][
j
j
j]的值该如何求得。
1、二维数组
每个物品只能选择一次或不选,物品i选择与否的条件是什么呢?
假设现在背包的状态是dp[ i i i-1][ j j j],即从前 { 1 , . . . , i − 1 } \{1,...,i-1\} {1,...,i−1}个物品挑选物品加入载重为 { 1 , . . . , j } \{1,...,j\} {1,...,j}的背包中的所有组合已知。下一步需要选择是否将物品 i ~i~ i 装入背包中,使得dp[ i i i][ j j j]最大,即从前 i ~i~ i 个物品中挑选物品装入载重为 j ~j~ j 的背包中,使在满足不超过载重 j ~j~ j 的同时背包中的物品总价值最大。首先物品 i ~i~ i 的重量不能超过载重 j ~j~ j ,同时选择i物品之后背包的总价值比不选择物品 i ~i~ i 时要大,即
for i i i in range(1,n+1): #前 i i i个物品#背包载重为 j ~j~ j ,这里 j ~j~ j 正序和倒序都行,因为dp是二维数组,dp[ i i i][:]的改变并不影响上一层状态dp[ i i i-1][:]
for j j j in range( w i w_i wi, W W W+1):dp[ i i i][ j j j] = max \max max{ dp[ i − 1 i-1 i−1][ j j j] , dp[ i − 1 i-1 i−1][ j − w i j-w_i j−wi] + v i v_i vi } #dp[ i i i][ j j j] 为物品 i ~i~ i 选择与否背包总价值较大者
设dp[ j j j]表示载重为 j j j的背包中的物品最大价值,下面来分析每个dp[ j j j]的值该如何求得。
1、一维数组
考虑到上面二维数组中,物品 i ~i~ i 选择与否只用到了第 i − 1 ~i-1~ i−1 层的数据,所以可以将数组变成一维的情况。分析情况和二维一模一样,这里只是用一维数组表示背包总价值而已,降低了空间复杂度。
for i in range(1,n+1): #前 i i i个物品#背包载重为 j ~j~ j ,这里 j ~j~ j 必须倒序,因为dp是一维数组,这里要保证用到的dp[ i i i][:]和dp[ j − w i j-w_i j−wi]是前一个状态的
for j in range( W W W, w i w_i wi-1, -1):dp[ j j j] = max \max max{ dp[ j j j] , dp[ j − w i j-w_i j−wi] + v i v_i vi } #dp[ j j j] 为物品 i ~i~ i 选择与否背包总价值较大者
完全背包问题
和01背包不同的是,完全背包中各种物品的选择可以是任意多的,即物品
i
~i~
i 可以选择任意多次,然后同样是求背包的总价值最大。
分析问题:在载重限制的条件下,物品
i
~i~
i 选择任意多次之后背包的总价值分析。
设dp[
i
i
i][
j
j
j]表示前
i
~i~
i 件物品在载重为
j
~j~
j 的背包中的最大价值,下面来分析每个dp[
i
i
i][
j
j
j]的值该如何求得。
1、二维数组
每个物品能选择任意多次,物品i选择与否的条件是什么呢?
和01背包的分析大致差不多,只是要加入在物品 i ~i~ i 重复选择的情况下,背包总价值的计算。若物品 i ~i~ i 可以取 { 0 , 1 , . . . , k } \{0,1,...,k\} {0,1,...,k}次,其中 k ∗ w i ≤ W k*w_i \leq W k∗wi≤W,则有
dp[ i i i][ j j j] = max \max max{ dp[ i − 1 i-1 i−1][ j j j] , dp[ i − 1 i-1 i−1][ j − k ∗ w i j-k*w_i j−k∗wi] + k* v i v_i vi },
除了这一点和01背包有差别之外,其他的都一样,所以只需要在01背包的基础上做改动即可,即
for i i i in range(1,n+1): #前 i i i个物品#背包载重为 j ~j~ j ,这里 j ~j~ j 正序和倒序都行,因为dp是二维数组,dp[ i i i][:]的改变并不影响上一层状态dp[ i i i-1][:];
#区别01背包中的dp[ i − 1 i-1 i−1][ j − w i j-w_i j−wi],完全背包中的dp[ i i i][ j − w i j-w_i j−wi]则是是否重复添加物品 i ~i~ i 的语句
for j j j in range( w i w_i wi, W W W+1):dp[ i i i][ j j j] = max \max max{ dp[ i − 1 i-1 i−1][ j j j] , dp[ i i i][ j − w i j-w_i j−wi] + v i v_i vi } #dp[ i i i][ j j j] 为物品 i ~i~ i 选择与否背包总价值较大者
设dp[ j j j]表示载重为 j j j的背包中的物品最大价值,下面来分析每个dp[ j j j]的值该如何求得。
1、一维数组
和01背包一维的情况类似。
for i in range(1,n+1): #前 i i i个物品#背包载重为 j ~j~ j ,这里 j ~j~ j 必须正序,正序保证了对后续最优解的影响
for j in range( w i w_i wi, W W W+1):dp[ j j j] = max \max max{ dp[ j j j] , dp[ j − w i j-w_i j−wi] + v i v_i vi } #dp[ j j j] 为物品 i ~i~ i 选择与否背包总价值较大者
具体的正序和逆序问题可以参考下面的文章!!!
和01背包问题一样,完全背包也可以用一维数组来保存数据。算法样式和01背包的很相似,唯一不同的是对V遍历时变为正序,而01背包为逆序。01背包中逆序是因为F[i][]只和F[i-1][]有关,且第i件的物品加入不会对F[i-1][]状态造成影响。而完全背包则考虑的是第i种物品的出现的问题,第i种物品一旦出现它势必应该对第i种物品还没出现的各状态造成影响。也就是说,原来没有第i种物品的情况下可能有一个最优解,现在第i种物品出现了,而它的加入有可能得到更优解,所以之前的状态需要进行改变,故需要正序。
————————————————
版权声明:本文为CSDN博主「wumuzi」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wumuzi520/article/details/7014830