1. 程式人生 > >動態規劃解決揹包問題

動態規劃解決揹包問題

1 揹包問題:給定n個重量為w1,w2...wn,價值為v1,v2...vn的物品和一個承重量為W的揹包,求這些物品中最有價值的一個子集,並且要能夠裝入揹包當中。

2 動態規劃:動態規劃與分治法都要求原問題的最優子結構,都是將問題分而治之,,不同的是動態規劃適用於交疊子問題的情況,分治法則適用於子問題相互獨立的問題

3 解題思路:為設計一個動態規劃的演算法,需要推匯出一個遞推關係,用較小子例項的解的形式來表示揹包問題的例項的解,讓我們考慮一個由前 i 個物品(1 <= i <= n)定義的例項,物品的重量分別為w1,w2...wi,價值分別為v1,v2...vi,揹包的承重量為  j  (1 <= j <=W)。設F(i, j)是該例項的最優解的價值總和,在這裡可以把前 i 個物品能夠放入承重量為 j 的揹包中的子集分成兩個類別,即把第 i 個物品放入揹包和不把第 i 個物品放入揹包

,如下。

(1)不把第 i 個物品放入揹包中的子集中,最優子集的價值是 F(i-1, j)

(2)把第 i 個物品放入揹包中的子集中,最優子集的價值vi + F(i-1, j-wi)

因此,在考慮前 i 個物品放入揹包的情況中,需要從上面兩個行為中選出價值大的子集,可得遞推式:

  F(i, j) = max(  F(i-1, j)  ,  vi + F(i-1, j-wi))

4 動態規劃程式碼展示

CAPACITY = 5    #  揹包容量
THINGS = 5    # 物品數量
w = [0, 3, 2, 1, 4, 5]  # 物品重量
v 
= [0, 25, 20, 15, 40, 50]  # 物品價值 def find_the_best_set(i, j): if i < 0 or j < 0:  # 當揹包容量或物品小於0時 return 0 if j - w[i] >= 0:  # 判斷第 i 個物品的質量與揹包容量比較 return max(find_the_best_set(i-1, j), find_the_best_set(i-1, j-w[i])+v[i])  # 從兩個情況中選擇最優解 else:    # 第 i 個 物品不能夠放入揹包中時
return find_the_best_set(i-1, j) # 從前 i-1 個物品中選擇最優解 if __name__ == '__main__': best_values = find_the_best_set(THINGS, CAPACITY) print(best_values)   # 輸出最優價值

5 動態規劃程式碼所涉及問題的解,滿足一個用交疊的子問題來表示的遞推關係,直接自頂向下這樣一個遞推關係要求一個演算法不止一次的計算公共子問題,因此效率非常低,另一方面,經典的動態規劃方法是自底向上的:它用所有較小的子問題的解填充表格,有些較小子問題的解常常不是必需的,由於這個缺點沒有在自頂向下中表現出來,所以我們希望能夠將自頂向下和自底向上的優勢結合起來,將需要的子問題求解並只解一次,這種方法是存在的,它是以記憶功能為基礎的

6 動態規劃及記憶功能程式碼展示

CAPACITY = 5  # 揹包容量
THINGS = 6  # 物品數量
W = [0, 2, 6, 1, 4, 5] # 物品重量
V = [0, 25, 20, 15, 40, 50]   # 物品價值
F = [[-1 for _ in range(CAPACITY+1)]for _ in range(THINGS)]  # 記憶陣列 初始值為-1
def find_the_best_set(i, j):
    value = 0  
    if i < 0 or j < 0: # 當揹包容量或物品小於0時
        return value
    if F[i][j] < 0:  # 判斷該情況是否存在記憶陣列中
        if j < W[i]:  # 判斷第 i 個物品的質量與揹包容量比較,第 i 個物品不能放入揹包中時
            value = find_the_best_set(i-1, j)   #從前 i-1 個物品中選擇最優解
        else:
            value = max(find_the_best_set(i-1, j), find_the_best_set(i - 1, j - W[i]) + V[i])  #選擇最優解
        F[i][j] = value  # 將該情況的最優解存入記憶陣列,避免二次計算
    return F[i][j]

if __name__ == '__main__':
    value = find_the_best_set(THINGS-1, CAPACITY)
    print(value)
    print(F)

 7 總結:以上僅為自己目前對於動態規劃解決揹包問題的一點淺薄看法,擴充套件的話還應該記錄選擇物品的編號並輸出,但是目前並沒有想到較好的解法,以後補充。