動態規劃------揹包問題
阿新 • • 發佈:2021-11-14
一、揹包問題之最大容量
1.問題描述:
假設揹包能裝9kg的東西,現在有五個物品分別是2,2,4,6,3kg,在不超過揹包容量的範圍內,能裝的最大容量是多少呢?
解法一:回溯法,即決策樹。
方法描述:從第一個物品到最後一個物品開始,做出決策,即裝或不裝,使用函式f(x,y)表示,其中x表示第X個物品,y表示第X個物品被裝或者沒有被裝後的物品總質量。最後形成的決策樹如下圖所示,左節點表示當前物品沒有被不裝,右節點表示當前物品被裝。
方法二:動態規劃
方法描述:將重量與物品數量裝換成矩陣,如下表所示
初始狀態:列表示物品編號,行表示總重量,用1所處位置表示當表當前物品被裝或不裝的總量
0kg | 1kg | 2kg | 3kg | 4kg | 5kg | 6kg | 7kg | 8kg | 9kg | |
0(2) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1(2) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2(4) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3(6) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4(3) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
第一個物品狀態:
0kg | 1kg | 2kg | 3kg | 4kg | 5kg | 6kg | 7kg | 8kg | 9kg | |
0(2) | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1(2) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2(4) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3(6) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4(3) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
如表所示,第一個物品不裝和被裝下的總量分別為0Kg,2kg(標1處
第二個物品狀態:
0kg | 1kg | 2kg | 3kg | 4kg | 5kg | 6kg | 7kg | 8kg | 9kg | |
0(2) | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1(2) | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2(4) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3(6) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4(3) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
如上表所示,第二個物品在第一個物品做出決策後,繼續做出決策(裝/不裝),總量分別為0,2,4kg,依此類推,到第五個物品做出決策後表如下所示
0kg | 1kg | 2kg | 3kg | 4kg | 5kg | 6kg | 7kg | 8kg | 9kg | |
0(2) | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1(2) | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2(4) | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
3(6) | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
4(3) | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
因此動態演算法之揹包問題程式碼如下所示
1 import numpy as np 2 #揹包基礎版本容量最大 3 def maxWeight(backp,backValues): 4 for j in range(len(backp)): 5 #第一個物品裝或不裝的狀態1 6 if j == 0: 7 #不裝 8 backp[j][0]=1 9 #裝 10 backp[j][2] = 1 11 else: 12 for i in range(len(backp[j])): 13 #查詢在上一個條件下(裝或不裝的物品) 14 if backp[j-1][i]==1: 15 #不裝物品 16 backp[j][i] = 1 17 #判斷上一個物品(裝或不裝的物品狀態)即用下標(重量)與當前物品重量之和是否超過總重量,不超過,標記為1 18 if i+backValues[j]<len(backp[j]): 19 backp[j][i+backValues[j]] = 1 20 21 22 23 for j in range(len(backp)): 24 25 for i in range(len(backp[j])): 26 27 #if backp[j][i] = 1 28 print(backp[j][i],end=" ") 29 print() 30 backp = np.zeros(shape=(5,10))#二維陣列5代表物品編號,10代表給定的要裝的總重量 31 print(len(backp)) 32 backValues = [2,2,4,6,3] 33 maxWeight(backp,backValues)
結果如下所示:
1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
二、揹包問題之最大價值
問題描述:給定五個物品,其重量分別是3、2、1、1、4,其價值分別是5、2、4、2、10,假設有個揹包總容量為8,在不超過揹包總容量的情況下,其能裝的最大價值是多少?
解題思路:本題中,出現了3個變數,分別是重量,容量,價值,我們用函式f(x,y,z)來表示
方法1:回溯法即決策樹,如下圖所示:
方法2:動態規劃如下表所示
0kg | 1kg | 2kg | 3kg | 4kg | 5kg | 6kg | 7kg | 8kg | |
0(3) | 0 | -1 | -1 | 5 | -1 | -1 | -1 | -1 | -1 |
1(2) | 0 | -1 | 2 | 5 | -1 | 7 | -1 | -1 | -1 |
2(1) | 0 | 4 | 2 | 6 | 9 | 7 | 11 | -1 | -1 |
3(1) | 0 | 4 | 6 | 6 | 9 | 11 | 11 | 13 | -1 |
4(4) | 0 | 4 | 6 | 6 | 10 | 14 | 16 | 16 | 19 |
因此動態演算法之揹包問題程式碼如下所示
1 import numpy as np 2 #揹包升級版本,加入價值體系 3 #backValues[j][0]為物品重量,backValues[j][1]物品價值 4 def maxWeightValues(backp,backValues): 5 goodsValues =np.zeros(shape=[len(backp[0])])#用於記錄當前重量的最大價值 6 for j in range(len(backp)): 7 #第一個物品裝或不裝的狀態1 8 if j == 0: 9 #不裝 10 backp[j][0]=0 11 #裝 12 backp[j][backValues[j][0]] = backValues[j][1] 13 goodsValues[backValues[j][0]] = backValues[j][1] 14 else: 15 for i in range(len(backp[j])): 16 #查詢在上一個條件下(裝或不裝的物品) 17 if backp[j-1][i] >=0 : 18 #不裝物品,判斷當前總重量的價值和與上一個物品狀態下(截止到當前被操作物品總重量的價值)總價值對比 19 if goodsValues[i] < backp[j-1][i]: 20 goodsValues[i] = backp[j-1][i] 21 backp[j][i] = backp[j-1][i] 22 else: 23 backp[j][i] = goodsValues[i] 24 #判斷截止到上一個物品總重量(裝或不裝的物品狀態)即用下標(重量)與截止到當前被操作物品總重量之和是否超過總重量,不超過,則物品裝進揹包裡面 25 if i+backValues[j][0]<(len(backp[j])): 26 #判斷當前總重量的價值和與截止到上一個被操作物品總重量的價值+當前物品的價值之和對比,以便求出最大價值。 27 if goodsValues[i+backValues[j][0]] < backp[j-1][i] + backValues[j][1]: 28 goodsValues[i + backValues[j][0]] = backp[j-1][i] + backValues[j][1] 29 backp[j][i+backValues[j][0]] = backp[j-1][i] + backValues[j][1] 30 else: 31 backp[j][i + backValues[j][0]] = goodsValues[i + backValues[j][0]] 32 #lists[i+backValues[j][0]].append(backp[j][i] + backValues[j][1]) 33 34 35 for j in range(len(backp)): 36 37 for i in range(len(backp[j])): 38 39 #if backp[j][i] = 1 40 print(backp[j][i],end=" ") 41 print() 42 image =[[-1 for col in range(9)] for row in range(5)] 43 backpValues = np.array(image) 44 45 46 47 backWeightValues = [(3, 5), (2, 2), (1, 4), (1, 2), (4, 10)] 48 maxWeightValues(backpValues,backWeightValues)
輸出結果:
0 -1 -1 5 -1 -1 -1 -1 -1 0 -1 2 5 -1 7 -1 -1 -1 0 4 2 6 9 7 11 -1 -1 0 4 6 6 9 11 11 13 -1 0 4 6 6 10 14 16 16 19