Given n items with size Ai and value Vi, and a backpack with size m. What's the maximum value can you put into the backpack?
Given 4 items with size [2, 3, 5, 7]
and value [1, 5, 2, 4]
, and a backpack with size 10
. The maximum value is 9
.
这是最经典的0-1背包问题。即有n件物品,每个物品有体积Ai, 价值Vi。然后有一个容量为m的背包,要求可以放入背包的最大价值。特点是每件物品只有一件,可以选择放或者不放。
定义状态,背包问题的经典定义,f[i,j]表示前i个物品当中选一些物品组成容量为j的最大价值。转换状态为对于第i 个物体取不取做一个选择。
即f[i,j] = max(f[i-1,j],f[i-1,j-A[i]]+V[i])前者为不取第i 个物体,后者为取第i 个物体。
初始化,注意这题不要求一定装满背包,所以初始化是f[0][j] =0, 如果要求装满,则f[0][0] = 0, f[0][j] = -∞。(来自背包九讲)。所以这里f[i,j]表示前i个物品当中选一些物品组成容量为j的最大价值,j只是容量,并不是精确的体积.
最终结果为f[n,m]。
注意在每次转换时,j的取值,如果取第i 个物体,则背包的大小必须大于Ai,否则无法做状态转换。所以在j小于A[i]时,直接取f[i-1,j]。
注意这题可以采用滚动数组做优化,毕竟每次都是对i做一个变换。对于j小于A[i]的情况,使用滚动数组也有优势,即完全不需要考虑j小于A[i]的情况,只需要直接继承就可以。非优化代码如下:
class Solution: # @param m: An integer m denotes the size of a backpack # @param A & V: Given n items with size A[i] and value V[i] # @return: The maximum value def backPackII(self, m, A, V): n = len(A) dp = [[0] * (m+1) for i in xrange(n+1)] for i in xrange(1,n+1): for j in xrange(0, m+1): dp[i][j] = dp[i-1][j] #非常重要,当j<A[i-1]时,只能默认取值为dp[i-1][j] if j >= A[i-1]: dp[i][j] = max(dp[i-1][j],dp[i-1][j-A[i-1]]+V[i-1]) return dp[n][m]
优化代码如下:
class Solution: # @param m: An integer m denotes the size of a backpack # @param A & V: Given n items with size A[i] and value V[i] # @return: The maximum value def backPackII(self, m, A, V): n = len(A) dp = [0] * (m+1) for i in xrange(0,n): for j in xrange(m, A[i]-1, -1): #注意逆序,因为此处需要利用的状态是dp[i-1][j]和dp[i-1][j-A[i]] dp[j] = max(dp[j],dp[j-A[i]]+V[i]) return dp[m]
可以看到非优化代码不仅浪费空间,在时间复杂度上也很浪费。必须做j的一个判断。所以以后默认使用滚动数组做优化。
来源:https://www.cnblogs.com/sherylwang/p/5621773.html