01背包问题

问题描述https://www.lintcode.com/problem/backpack-ii/description

125. 背包问题 II

有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值.

问最多能装入背包的总价值是多大?

关键点:

1.定义dp数组,dp[i][j]表示前i个物品,在背包大小为j的情况下的最大价值,dp[m][n]就是要求的结果。

2.求解过程。
   没有商品,任意背包大小,最大价值都为0. 即dp[0][0] = 0, dp[0][1] = 0, ... , dp[0][n] = 0。
   前一个商品,背包大小为0到m, 最大价值分别为dp[1][0], dp[1][1], ... , dp[1][n]
   前两个商品,背包大小为0到m, 最大价值分别为dp[2][0], dp[2][1], ... , dp[2][n]
   ...
   前i个商品,背包大小为0到m, 最大价值分别为dp[i][0], dp[i][1], ... , dp[i][n]

3.递推公式。dp[i][j] 与dp[i - 1][x]的关系, x属于[0, j]。 即“只有前i个物品且背包大小为j的总价值”与“只有前i-1个物品,背包大小为0到j”的关系. (A[i - 1]表示第i个商品的大小,V[i - 1]表示第i个商品的)
   共有两种情况, 装入第i个商品或者不装入第i个商品。
     装入第i个商品,则dp[i][j] = dp[i - 1][j - A[i - 1]] + V[i - 1]
     不装入第i个商品,则dp[i][j] = dp[i - 1][j]
   即递推公式为dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - A[i - 1]] + V[i - 1])

class Solution:
    """
    @param m: An integer m denotes the size of a backpack
    @param A: Given n items with size A[i]
    @param V: Given n items with value V[i]
    @return: The maximum value
    """
    def backPackII(self, m, A, V):
        # write your code here
        dp = [[0] * (m + 1) for i in range(len(A) + 1)]
        for i in range(1, len(A) + 1):
            for j in range(1, m + 1):
                dp[i][j] = 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[-1][-1]

def test():
        s = Solution()
        print s.backPackII(10, [3, 4, 8, 5], [1, 5, 2, 4]) == 9
        print s.backPackII(10, [2, 3, 8], [2, 5, 8]) == 10

if __name__ == '__main__':
        test()

dp空间优化分析1

1.dp[i][j]和dp[i - 1][x]有关系和其它所有行都没有关系, 因此可以用两行数组代替一个二维数组。dp_last表示上一行,dp_cur表示当前行。除dp变量其它逻辑没变。

(下面的dp_last = copy.deepcopy(dp_cur)通过值拷贝,否则dp_cur, dp_last两个变量指向同一块数据,更新dp_cur也同样更新了dp_last)

import copy

class Solution:
    """
    @param m: An integer m denotes the size of a backpack
    @param A: Given n items with size A[i]
    @param V: Given n items with value V[i]
    @return: The maximum value
    """
    def backPackII(self, m, A, V):
        # write your code here
        dp_last = [0] * (m + 1)
        dp_cur = [0] * (m + 1)
        for i in range(1, len(A) + 1):
            for j in range(1, m + 1):
                dp_cur[j] = dp_last[j]
                if j >= A[i - 1]:
                    dp_cur[j] = max(dp_last[j], dp_last[j - A[i - 1]] + V[i - 1])
            dp_last = copy.deepcopy(dp_cur)
        return dp_cur[-1]

def test():
        s = Solution()
        print s.backPackII(10, [3, 4, 8, 5], [1, 5, 2, 4]) == 9
        print s.backPackII(10, [2, 3, 8], [2, 5, 8]) == 10

if __name__ == '__main__':
        test()

dp空间优化分析2

1.dp[i][j]和dp[i - 1][x]有关系和其它所有行都没有关系,与当前行也没有关系。因此可以顺序求dp[i][0], dp[i][1], ..., dp[i][m], 也可以逆序求dp[i][m], dp[i][m - 1], ..., dp[i][0]。 
2.dp[i][j]只和前一行第x列元素有关(x属于[0, j]). 如果逆序求dp[i][j],这样dp_cur和dp_last可以合并, 因为更新dp_cur[j]的时候只需利用到dp_last第前j列的元素。而因为是逆序更新,更新dp_cur[j]的时候,dp_cur第前j列都没有变。
 

import copy

class Solution:
    """
    @param m: An integer m denotes the size of a backpack
    @param A: Given n items with size A[i]
    @param V: Given n items with value V[i]
    @return: The maximum value
    """
    def backPackII(self, m, A, V):
        # write your code here
        dp = [0] * (m + 1)
        for i in range(1, len(A) + 1):
            for j in range(m, 0, -1):
                if j < A[i - 1]:
                    break
                dp[j] = max(dp[j], dp[j - A[i - 1]] + V[i - 1])
        return dp[-1]

def test():
        s = Solution()
        print s.backPackII(10, [3, 4, 8, 5], [1, 5, 2, 4]) == 9
        print s.backPackII(10, [2, 3, 8], [2, 5, 8]) == 10

if __name__ == '__main__':
        test()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值