0-1 背包問題

動(dòng)態(tài)規(guī)劃 遞歸 Python


問題描述:在M件物品取出若干件放在空間為W的背包里,每件物品的體積為W1,W2……Wn,與之相對應(yīng)的價(jià)值為P1,P2……Pn。求出獲得最大價(jià)值的方案。
注意:在此問題中,所有的體積值均為整數(shù)。01的意思是,每個(gè)物品都是一個(gè)整體,要么整個(gè)都要,要么都不要。


  • 最優(yōu)子結(jié)構(gòu)

考慮所有物品的子集合,考慮第n個(gè)物品都有兩種情況: 1. 包括在最優(yōu)方案中 2. 不在最優(yōu)方案中因此,能獲得的最大價(jià)值,即為以下兩個(gè)值中較大的那個(gè):

  1. 在剩下 n-1 個(gè)物品中(剩余 W 重量可用)的情況能得到的最大價(jià)值 (即排除了 第n個(gè)物品)
  2. 第n個(gè)物品的價(jià)值 加上 剩下 剩下的 n-1 個(gè)物品(剩余W- wn的重量)能得到的最大價(jià)值。(即包含了第n個(gè)物品)

如果第n個(gè)物品的重量,超過了當(dāng)前的剩余重量W,那么只能選情況1), 排除第n個(gè)物品。


由上面的最優(yōu)子結(jié)構(gòu),可以得到一個(gè)遞歸解法:

def kanpSack_rec(W,wt,val,n):
    if n==0 or W == 0:
        return 0
    # 如果第n個(gè)物品的重量超過背包容量W,這件物品就不能被加進(jìn)背包
    if (wt[n-1] > W):
        return kanpSack_rec(W,wt,val,n-1)
    # 返回下面兩種情況中的最大值:
    # (1) 第n個(gè)物品被放進(jìn)背包中
    # (2) 沒被放進(jìn)背包
    else:
        return max(val[n-1]+kanpSack_rec(W-wt[n-1],wt,val,n-1),kanpSack_rec(W,wt,val,n-1))

這種方法其實(shí)就是搜索了所有的情況,但是有很多重復(fù)的計(jì)算。時(shí)間復(fù)雜度是指數(shù)級的 O(2^n)。


0-1背包滿足動(dòng)態(tài)規(guī)劃算法的兩個(gè)基本屬性(重疊子問題和最優(yōu)子結(jié)構(gòu))。可以通過自下而上的打表,存儲(chǔ)中間結(jié)果,來避免重復(fù)計(jì)算。即:欲求前i個(gè)物體放入容量為m(kg)背包的最大價(jià)值c[i][m]——使用一個(gè)數(shù)組來存儲(chǔ)最大價(jià)值。而前i個(gè)物體放入容量為m(kg)的背包,又可以轉(zhuǎn)化成前(i-1)個(gè)物體放入背包的問題。下面使用數(shù)學(xué)表達(dá)式描述它們兩者之間的具體關(guān)系,表達(dá)式中各個(gè)符號的具體含義:

wt[i] :            第i個(gè)物體的重量
val[i] :           第i個(gè)物體的價(jià)值
K[i][w] :         前i個(gè)物體放入容量為w的背包的最大價(jià)值
K[i-1][w] :       前i-1個(gè)物體放入容量為w的背包的最大價(jià)值
K[i-1][W-wt[i]] : 前i-1個(gè)物體放入容量為M-wt[i]的背包的最大價(jià)值;
由此可得:
c[i][m]=max{c[i-1][m-w[i]]+val[i] , c[i-1][m]}

解法如下:

def knapsack_norec(W,wt,val,n):
    K = [[0 for x in range(W+1)] for x in range(n+1)]
    # 從底向上構(gòu)建K[][]表
    for i in range(n+1):
        for w in range(W+1):
            if i==0 or w==0:
                K[i][w] = 0
            elif wt[i-1] <= w:
                K[i][w] = max(val[i-1]+K[i-1][w-wt[i-1]],K[i-1][w])
            else:
                K[i][w] = K[i-1][w]
    return K[n][W]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容