1. 程式人生 > 其它 >動態規劃------揹包問題

動態規劃------揹包問題

一、揹包問題之最大容量

 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