1.前言
第368场leetcode周赛第二题使用到了0 1背包问题的解法,由于当时对0 1背包问题理解不是很透彻,导致这题丢分。在b站上看了启蒙课程再加上自己理解,于是有了这篇博客,一是方便自己复习总结,二是为算法小白提供帮助。
2.状态方程及其推导的说明
0 1背包的状态方程是: d p [ i ] [ j ] = M A X { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] } dp[i][j]=MAX\{dp[i-1][j],dp[i-1][j-weight[i]]+value[i]\} dp[i][j]=MAX{dp[i−1][j],dp[i−1][j−weight[i]]+value[i]}。关于这个方程的推导,由于作者水平有限,本文直接使用该方程,将来如果理解了推导过程会更新本文,感兴趣的朋友可以去看相关的文章
2.1 状态方程解读
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]: 当背包容量为j时,物品0-i任取放满背包获得的最大价值。这里的任取指的是:所有物品至多取一次,可能都取,可能都不取,也可能取一部分。对于某个物品,取还是不取,需要使用方程来进行决策。
d
p
[
i
−
1
]
[
j
]
dp[i−1][j]
dp[i−1][j]: 背包容量为j的情况下,当从物品0遍历到物品i时,决定不将物品i其放入背包获得的最大价值,这等价于将物品0~i-1任取放入背包获得的最大价值。
d
p
[
i
−
1
]
[
j
−
w
e
i
g
h
t
[
i
]
]
+
v
a
l
u
e
[
i
]
dp[i-1][j-weight[i]]+value[i]
dp[i−1][j−weight[i]]+value[i]: 背包容量为j的情况下,当从物品0遍历到物品i时,决定将物品i其放入背包(假设放得下)获得的最大价值。这等价于将物品0~i-1任取使得容量占用为
j
−
w
e
i
g
t
[
i
]
j-weigt[i]
j−weigt[i]时对应的最大价值dp[i-1][j-weight[i]],再加上把剩余容量weigt[i]给物品i放入(物品i的价值为value[i])获得的价值value[i](这个值是确定的),即
d
p
[
i
−
1
]
[
j
−
w
e
i
g
h
t
[
i
]
]
+
v
a
l
u
e
[
i
]
dp[i-1][j-weight[i]]+value[i]
dp[i−1][j−weight[i]]+value[i]。
2.2状态方程初始化
物品是数组value[]的下标i表示的,当i=0时,i-1<0,方程 d p [ i ] [ j ] = M A X { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] } dp[i][j]=MAX\{dp[i-1][j],dp[i-1][j-weight[i]]+value[i]\} dp[i][j]=MAX{dp[i−1][j],dp[i−1][j−weight[i]]+value[i]}会报数组越界异常,因此必须对i=0的情况单独处理,对于 d p [ 0 ] [ j ] dp[0][j] dp[0][j],只要 j > = w e i g h t [ 0 ] j>=weight[0] j>=weight[0],那么 d p [ 0 ] [ j ] = v a l u e [ 0 ] dp[0][j]=value[0] dp[0][j]=value[0];