問題描述:有乙個揹包容量為m,一堆物品其重量表示為w=,物品相應的價值v=,現在要求將物品中的一部分或全部,放入揹包。要求:裝入物品的總價值最高;同時滿足裝入物品總重量不超過m;對單個物品而言,狀態可為:裝入揹包、不裝入揹包、一部分裝入揹包。
假設裝入的物品為從w(i)到w(j),則有:
對於完全揹包而言,我們採用的常見演算法為:貪心演算法。貪心規則為:每次放入的物品必須滿足單位重量價值最高,即v(i)/w(i)最大。
第一步:計算單位重量價值:
第二步:放物品,按照單位重量價值來說6>5>4,因此放入順序為w(1)、w(2)、w(3)。
顯然w(1)完全放入後,揹包未滿;因此完全放入w(2)後,揹包仍未滿;但是此時若繼續全部放入w(3),顯然無法全部放入,只能放入三分之二的w(3)。
相對於完全揹包問題而言,0/1揹包問題多了一條規則:
物品放入規則,要麼全部放入,要麼不放入;不能部分放入!!
這個看似把問題簡單化的規則,實際上讓問題變得更加複雜。仔細想想就知道先前的貪心演算法在這裡失效了。因為前面的貪心規則無法保證單位重量價值最大物品一定被取到。
對於0/1揹包問題,常採用的演算法是:動態規劃。之前的一篇關於動態規劃詳細講解的文章:
顯然對於動態規劃而言,最核心的事情就是尋找「狀態轉移函式」!!!
在尋找狀態轉移函式之前,說說下面這個裝包過程最注意的一點就是,我們是嘗試性裝包,也就是說,一邊往裡面放,但受容量限制,還有可能拿走揹包裡面之前的物品,以滿足不超重!!!尋找狀態轉移函式:
(1)假設我們正在將物品向背包裡面瞎裝一通,此時恰好裝到第i個物品。
(2)假設我們運氣足夠好,前面裝了的i-1個恰好是區域性最優解。換句話說,不可能找到其他i-1個物品放進揹包能擁有更大的效益值。
(3)由於是0/1揹包問題,此時我們必須要決定第i個物品到底放不放入揹包?在這裡,放入不放入最直觀的解釋就是:如果放入物品,整個效益值提高,就決定放入;反之,則不放入。這裡要注意了,因為我們是既往裡面裝,又可能往外面拿的過程。受容量限制,可能你把第i個放進去了,同時也需要從裡面拿乙個出來。!自然分兩種情況討論;
(4)當第i個物品不放入揹包時,設設總的效益值為c[i-1,j],其中i-1表示揹包中已經放入了i-1個物品,j表示揹包的容量。(這裡的i,j主要是為了程式設計的方便,因為是通過迴圈的方式逐漸增大i,j來選擇物品是否放入的,可參考圖1。)
(5)當第i個物品放入揹包,放入揹包之後,總的效益值就應該為c[i-1,j-w(i)]+v(i),其中i表示揹包中已經放入了i個物品,j-w(i)表示揹包剩餘的容量。
(6)比較c[i-1,j]和c[i-1,j-w(i)]+v(i)的大小,來決定是否放入。如果c[i-1,j]
因此狀態轉移方程為:
計算情況如圖1:
**實現:
############################
#動態規劃之0/1揹包問題
#by:zkj
#2023年12月18日
############################
from numpy import zeros
def pack(weight,value,capacity):
itemcnt = len(weight) #物品數量
totalvalue = zeros([itemcnt+1,capacity+1],int) #存放歷史最優解的陣列
for i in range(0,itemcnt+1): ##狀態轉移函式實現
for j in range(0,capacity+1):
if (i == 0) or (j == 0):
totalvalue[i][j] = 0
elif j < weight[i-1]:
totalvalue[i][j] = totalvalue[i-1][j]
else:
totalvalue[i][j] = max(totalvalue[i-1][j],totalvalue[i-1][j-weight[i-1]] + value[i-1])
return totalvalue
def printresult(totalvalue,weight,value,capacity):
itemcnt = len(weight)
print("揹包能裝的最大效益值:\n",max(totalvalue[itemcnt]))
print("裝入揹包的物品有:")
i = itemcnt;j = capacity
while i >= 0:
if totalvalue[i][j] == totalvalue[i-1][j-weight[i-1]] + value[i-1]:
print(i,end = "") #結尾不換行
j = j-weight[i-1]
i -=1
return
weight = (5,3,7,4) #物品重量
value = (3,2,9,5) #物品價值
maxcapacity = 15 #揹包容量
statemat = pack(weight,value,maxcapacity)
printresult(statemat,weight,value,maxcapacity)
PHP經典演算法之揹包問題
問題 假設有乙個揹包的負重最多可達8公斤,而希望在揹包中裝入負重範圍內可得之總價物品,假設是水果好了,水果的編號 單價與重量如下所示 1 栗子 4kg 4500 2 蘋果 5kg 5700 3 橘子 2kg 2250 4 士多啤梨 1kg 1100 5 甜瓜 6kg 6700 分析 揹包問題是關於最...
經典演算法問題 0 1 揹包
一 問題描述 有n 個物品,它們有各自的重量和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?二 問題分析 1 用v i 表示物品價值,w i 表示物品重量。定義狀態dp i j 以j為容量為放入前i個物品 按i從小到大的順序 的最大價值。2 初始化邊界條件,v 0,j v i,...
經典演算法詳解 之 揹包演算法
揹包問題 knapsackproblem 是一種組合優化的 np完全問題 問題可以描述為 給定一組物品,每種物品都有自己的重量和 在限定的總重量內,我們如何選擇,才能使得物品的總 最高。這個問題涉及到了兩個條件 一是物品總的大小小於或等於揹包的大小,二是物品總的價值要盡量大。如果我們 用子問題定義狀...