經典演算法之 揹包問題

2021-07-25 11:24:34 字數 3048 閱讀 3259

問題描述:有乙個揹包容量為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完全問題 問題可以描述為 給定一組物品,每種物品都有自己的重量和 在限定的總重量內,我們如何選擇,才能使得物品的總 最高。這個問題涉及到了兩個條件 一是物品總的大小小於或等於揹包的大小,二是物品總的價值要盡量大。如果我們 用子問題定義狀...