[動態規劃系列] —— 揹包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組合總和 Ⅳ

相關文章
相關標籤/搜索