考慮乙個場景:當你有去沙漠旅行,你有乙個揹包和一些物品,揹包有最大承受重量,物品也有重量和價值,而物品種類很多,不可能全都裝在揹包裡,如何去選取價值總量最高的物品組合呢?
物品名價值
water
10book
3food
9jacket
5camera
6物品名
重量water
3kgbook
1kgfood
2kgjacket
2kgcamera
1kg考慮使用貪婪演算法,那就是什麼價值高就優先拿什麼,但有時這種近似解會不准,這時就要採用動態規劃方法:從小問題入手,逐步解決大問題,可以幫助你在給定約束條件下找到最優解
首先定義乙個**,橫座標是揹包重量,縱座標是物品名稱,填入值是當前物品,當前揹包重量的最大價值:
物品/揹包重量
1kg2kg
3kg4kg
5kg6kg
water
book
food
jacket
camera
動態規劃的解決方案就是把這張表填好,然後根據揹包重量選擇在該重量下最大價值所組成的物品
填入規則:每一行只能拿取當前行和之前行的物品
先看第一行water,這時只有water,沒有之前的物品,而water的重量是3kg,那麼在1kg,2kg的揹包就裝不下water,在3kg以上重量的揹包就可以放入water,結果如下:
注:這時候只有水,沒有其他的
現在再看第二行book,這時候可以拿的物品就有book和water,而book的重量是1kg
在1kg揹包時可以放入book
2kg揹包也只能放book(water放不下)
當3kg的揹包時,這時候會面臨選擇,因為water的重量是3kg,可以放water,也可以放book,那麼取價值最大的放進揹包(water的價值是10,book是3)
當4kg的揹包時,water和book的總重正好是4kg,這時可以把這兩個都放進去,所以第二行結果如下:
再看第三行,這時候可以拿water,book,food
在1kg揹包時還是只能放下book
當2kg揹包時多了個選項,因為food的重量是2kg,所以去價值最大的放在包裡(food的價值是9)
3kg的時候的選擇有:(1)放入water,(2)放入book,food,對比價值大小選擇放入book和food,
4kg時根據價值最大原則,放入food和water
5kg時放入water和food
6kg是放入water,food,book剛好都放下了
結果為:
第四行和第五行也是採用這樣的策略填入價值,最終結果為:
其實這裡填的數字是有規律的:
現為方便說明把上面的圖表轉化為矩陣為:
那麼填入的原則為:
table[i][j]= max(table[i-1][j],當前商品的價值+剩餘空間價值(table[i-1][j-當前商品重量]))
注:如果處於特殊位置,如table[0][0]單元格,沒有table[i-1][j]那麼就是0
例:table[3][4]=max(table[2][4],worth(jacket)+table[2][4-weight(jacket)])
=max(19,5+10)
=19與之前一步步推算的結果一致
又例:table[0][4]=max(table[0-1][4],worth(water)+table[0-1][4-weight(water)] (因為是第一行,所以有些資料是空的,定為0)
=max(0,10+0)
=10同樣與之前推算的結果一致
那既然有邏輯有公式,那就可以寫**了:
python版本3.6
使用庫:numpy
#動態規劃
import numpy as np
#定義重量
weight={}
weight["water"]=3
weight["book"]=1
weight["food"]=2
weight["jacket"]=2
weight["camera"]=1
#定義價值
worth={}
worth["water"]=10
worth["book"]=3
worth["food"]=9
worth["jacket"]=5
worth["camera"]=6
#存放行標對應的物品名:
table_name={}
table_name[0]="water"
table_name[1]="book"
table_name[2]="food"
table_name[3]="jacket"
table_name[4]="camera"
#建立矩陣,用來儲存價值表
table=np.zeros((len(weight),6))
#建立矩陣,用來儲存每個單元格中的價值是如何得到的(物品名)
table_class=np.zeros((len(weight), 6), dtype=np.dtype((np.str_,500)))
for i in range(0,len(weight)):
for j in range(0,6):
# 獲取重量
this_weight = weight[table_name[i]]
# 獲得價值
this_worth = worth[table_name[i]]
#獲取上乙個單元格 (i-1,j)的值
if(i>0):
before_worth=table[i-1,j]
#獲取(i-1,j-重量)
temp=0
if(this_weight<=j):
temp=table[i-1,j-this_weight]
#(i-1,j-this_weight)+求當前商品價值
#判斷this_worth能不能用,即重量有沒有超標,如果重量超標了是不能加的
synthesize_worth=0
if(this_weight-1<=j):
synthesize_worth=this_worth+temp
#與上乙個單元格比較,哪個大寫入哪個
if(synthesize_worth>before_worth):
table[i,j]=synthesize_worth
if(temp==0):
#他自己就超過了
table_class[i][j] = table_name[i]
else:
# 他自己和(i-1,j-this_weight)
table_class[i][j] = table_name[i] + "," + table_class[i - 1][j - this_weight]
else:
table[i,j]=before_worth
table_class[i][j]=table_class[i-1][j]
else:
#沒有(i-1,j)那更沒有(i-1,j-重量),就等於當前商品價值,或者重量不夠,是0
if(this_weight-1<=j):
table[i,j]=this_worth
table_class[i][j]=table_name[i]
print(table)
print("--------------------------------------")
print(table_class)
最終結果:
如圖紅框部分可知:當揹包重量為6kg是,選擇camera,food,water可使價值最大
python 動態規劃實現整數拆分
我們先來看這樣乙個問題 把5拆分成若干無序正整數的和 若干可以包含1 請問有多少種拆分方法?直接用列舉法實現 5 5 5 4 1 5 3 2 5 3 1 1 5 2 2 1 5 2 1 1 1 5 1 1 1 1 1 很顯然,結果為7。注意這裡5 4 1和5 1 4是相同的,只計算為一種方法。如果計...
python動態規劃
思路 把每次的結果放在字典裡 from functools import wraps defmemo func cache wraps func defwrap args if args not in cache cache args func args return cache args retu...
動態規劃python
問題描述 最長遞迴子串行即給定乙個序列,求解其中最長的遞增的子串行的長度 注意 在求解過程中,長度為n的遞增子串行可能不止乙個,但是在所有長度為n的子串行中,有乙個子串行是比較特殊的,那就是最大元素最小的遞增子序 def getdp1 arr n len arr dp 0 nfor i in ran...