Backpack II 0-1背包

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的一个判断。所以以后默认使用滚动数组做优化。

posted on 2016-06-27 22:17  Sheryl Wang  阅读(255)  评论(0编辑  收藏  举报

导航