最清楚的01揹包問題講解

2022-03-11 17:17:41 字數 3193 閱讀 9268

題目:

01揹包問題描述:有編號分別為a,b,c,d,e的n=5件物品,它們的重量w分別是2,2,6,5,4,它們的價值v分別是6,3,5,4,6,每件物品數量只有乙個,現在給你個承重為m=10的揹包,如何讓揹包裡裝入的物品具有最大的價值總和sum_v?

在dp(dynamic programming,動態規劃)問題中,01揹包問題是比較基礎和簡單的了,但是網上很多人的講解要麼長長一大段,長篇公式理論,要麼就是知識把狀態轉移方程列了出來,而沒有說明為什麼方程是這麼寫的,下面我力圖將01揹包問題中最簡單最核心的概念和思路講一下

1.此01揹包問題本質上是窮舉揹包容量和可供選擇的物品(意思是裡面的物品可能會放進揹包,可能不會放進揹包),取得最優解,只不過在窮舉的過程中,會根據狀態轉移方程,只計算可能獲得的最優解的部分,不去計算不是最優解的部分。具體來看,解題思路是把該問題分解為乙個乙個的小問題,一步步的通過小問題的最優解,最終得到大問題的最優解,跟我們人腦解題的思路是一樣的。比如第乙個小問題是「當我的揹包承重m=1,只有編號為a的物品可供選擇時,最優解是什麼」,然後下乙個小問題是建立在前乙個小問題的基礎上「當我的揹包承重m=1,有編號為a,b的物品可供選擇時,最優解是什麼」,以此類推。

2.為什麼能列出狀態轉移方程?是因為每個狀態的最優解,都是根據之前的狀態的最優解獲得的。具體到揹包問題,有以下幾點:

a) 當物品備選情況(物品備選情況指:可供選擇的物品的集合)一致時,揹包容量m越大,那麼sum_v一定大於等於原來的值。

b) 揹包容量m確定時,可供選擇的物品n越多,那麼sum_v一定大於等於原來的值。

c)由a)和b)可得,sum_v的最大值就是當m和n取到最大值時的sum_v

c) 從思路上說,01揹包問題有兩個維度:揹包容量m,和供選擇物品數n。程式設計的本質是實現人類解決現實問題的思路。仔細想想,如果不借助計算機,你該如何解決這個問題?答案是,例如考慮m=1時,先考慮a能否放入揹包,取得最大值,再考慮a和b能否放入揹包(a和b都是備選,最終放入揹包的可能是a,可能是b,也可能是ab),這時因此與之前只考慮a的情況相比,多了乙個b,所以:

用數學的方式描述上段話:sum_v[i][j]表示將前i件物品列為備選,揹包容量為j時,能獲得的最大價值;w[i]表示第i件物品的重量,v[i]表示第i件物品的價值

#此時揹包容量 m=1

if 1 >=w[2]:

sum_v[2][1] = max(sum_v[1][j-w[2]] + v[2], sum_v[1][1])

else

: sum_v[2][1] = sum_v[1][1]

推廣到任意情況,即得到我們的狀態轉移方程

if j >=w[i]:

sum_v[i][j] = max(sum_v[i-1][j-w[i]] + v[i], sum_v[i-1][j])

else

: sum_v[i][j] = sum_v[i-1][j]

sum_v的最大值就是sum_v[i][j]的最後乙個元素

如何讀圖: 例如填充紅色格仔這裡,指在容量m=3,將a,b,c,d 這4件物品考慮在內時,可以取得的最大價值。

3. 計算時進行簡單的資料結構改造。因為當i=1時,即計算開始階段,還要考慮到如果第1件物品放不進去的情況,此時沒有物品在揹包中,因此重量和價值都是0.因此需要在表示物品重量和價值的列表前加乙個資料0。

另外,當沒有物品在揹包中時,價值為0.所以需要sum_v[i][j]初始值全部設為0.

下面是詳細**:

#

!/usr/bin/env python3

#-*- coding:utf-8 -*-

import

copy

class

zopack(object):

def__init__

(self,n,m,w,v):

self.num =n

self.capacity =m

self.weight_list = [0,] +w

self.value_list = [0,] +v

self.sum_value_metrix = self.__createmetrix__(self.num+1,self.capacity+1,0)

def__createmetrix__

(self,x,y,init_value):

d2_list =

for i in

range(x):

d1_list =

for j in

range(y):

return

d2_list

defdp(self):

sum_v =self.sum_value_metrix

num =self.num

capacity =self.capacity

w =self.weight_list

v =self.value_list

for i in range(1,num+1):

for j in range(1,capacity+1):

if j >=w[i]:

#print("i,j:%s,%s" % (i,j))

sum_v[i][j] = max(sum_v[i-1][j-w[i]] + v[i], sum_v[i-1][j])

else

: sum_v[i][j] = sum_v[i-1][j]

print("

the max value we can get is:

", sum_v[-1][-1])

print

(sum_v)

if__name__ == "

__main__":

num = 5capacity = 10weight_list = [2, 2, 6, 5, 4]

value_list = [6, 3, 5, 4, 6]

q =zopack(num,capacity,weight_list,value_list)

q.dp()

最通俗易懂的01揹包問題講解

1 動態規劃 dp 動態規劃 dynamic programming,dp 與分治區別在於劃分的子問題是有重疊的,解過程中對於重疊的部分只要求解一次,記錄下結果,其他子問題直接使用即可,減少了重複計算過程。另外,dp在求解乙個問題最優解的時候,不是固定的計算合併某些子問題的解,而是根據各子問題的解的...

動態規劃之01揹包問題(最易理解的講解)

01揹包問題,是用來介紹動態規劃演算法最經典的例子,網上關於01揹包問題的講解也很多,我寫這篇文章力爭做到用最簡單的方式,最少的公式把01揹包問題講解透徹。f i,j 表示在前i件物品中選擇若干件放在承重為 j 的揹包中,可以取得的最大價值。pi表示第i件物品的價值。決策 為了揹包中物品總價值最大化...

揹包問題 01揹包問題

n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...