[动态规划系列] —— 背包DP之彻底背包

彻底背包问题

有n个物品,1个容量v的背包,第i个物品体积是volume[i],价值是value[i],问将哪些物品装入背包,可以使这些物品的整体积不超过背包容量,且总价值最大,每一个物品能够使用无限次。

若是你阅读过个人上一篇文章01背包,那么彻底背包问题的代码只须要在其基础之上做很小的改动。在01背包的状态压缩中咱们提到,j值须要向左增加,保证可以正确的引用到上一次状态的结果。python

而如果j值向右增加,那么咱们引用的“上一次状态”其实是已经被更新的当前次的状态,这一步的含义指当前物品能够被重复选择,而这刚好就是彻底背包问题。post

def solution(n, v, volume, value):
    status = [0]*(v+1)
    for i in range(1, n+1):
        for j in range(volume[i-1], v+1): # 相比于01背包,只有这一行作了改动
            status[j] = max(status[j], value[i-1] + status[j-volume[i-1]])
    return status[v]

若是上面的解释尚未理解,继续向下看,但请确保你已经理解了01背包问题优化


首先回忆01背包中status[i][j] = max(status[i-1][j], value[i-1] + status[i-1][j-volume[i-1]])的含义。code

在状态转移的过程当中,咱们考虑前i-1件物品的状态,和是否选择第i件物品,保证了01背包问题中每一个物品只能选择一次的特性。leetcode

而对于彻底背包问题,每件物品能够无限使用,也就是对于第i件物品,咱们能够重复选择,在这种状况下,status[i][j]能够由status[i][j-volume[i-1]]转移而来。get

def solution(n, v, volume, value):
    status = [[0]*(v+1) for _ in range(n+1)]
    for i in range(1, n+1):
        for j in range(1, v+1):
            if j - volume[i-1] >= 0:
                status[i][j] = max(status[i-1][j], value[i-1] + status[i][j-volume[i-1]]) # 相比于01背包,只有这一行作了改动
            else: status[i][j] = status[i-1][j]
    return status[n][v]

一样的,咱们对彻底背包版本的代码做状态压缩。io

def solution(n, v, volume, value):
    status = [0]*(v+1)
    for i in range(1, n+1):
        for j in range(1, v+1):
            if j - volume[i-1] >= 0:
                status[j] = max(status[j], value[i-1] + status[j-volume[i-1]]) # 相比于01背包,只有这一行作了改动
            else: status[j] = status[j]
    return status[v]

咱们会发现状态压缩后,彻底背包和01背包的状态转移方程一致,考虑01背包的j为什么要向左增加?是由于01背包中须要还没有更新的status[j-volume[i-1]],也就是status[i-1][j-volume[i-1]]class

而彻底背包须要的是status[i][j-volume[i-1]],即已经更新的status[j-volume[i-1]],因此j须要向右增加,再对分支结构作简单的优化,能够获得最终版本彻底背包问题的代码。基础

def solution(n, v, volume, value):
    status = [0]*(v+1)
    for i in range(1, n+1):
        for j in range(volume[i-1], v+1):
            status[j] = max(status[j], value[i-1] + status[j-volume[i-1]])
    return status[v]

这也就是本文最开始给出的代码。引用

之因此该问题被称做彻底背包,其缘由在于对于每同样物品能够使用无限次。在咱们遇到的题目中,每每是彻底背包问题的变体,咱们须要学会如何将题目转换为经典的彻底背包问题。

相关题目:零钱兑换 II组合总和 Ⅳ

相关文章
相关标签/搜索