動態規劃 01揹包問題(通俗易懂,超基礎講解)

2021-10-04 03:38:57 字數 3242 閱讀 5703

有n個物品,它們有各自的體積和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?

為方便講解和理解,下面講述的例子均先用具體的數字代入,即:eg:number=4,capacity=8

i(物品編號)12

34w(體積)23

45v(價值)34

56根據動態規劃解題步驟(問題抽象化、建立模型、尋找約束條件、判斷是否滿足最優性原理、找大問題與小問題的遞推關係式、填表、尋找解組成)找出01揹包問題的最優解以及解組成,然後編寫**實現。

動態規劃與分治法類似,都是把大問題拆分成小問題,通過尋找大問題與小問題的遞推關係,解決乙個個小問題,最終達到解決原問題的效果。但不同的是,分治法在子問題和子子問題等上被重複計算了很多次,而動態規劃則具有記憶性,通過填寫表把所有已經解決的子問題答案紀錄下來,在新問題裡需要用到的子問題可以直接提取,避免了重複計算,從而節約了時間,所以在問題滿足最優性原理之後,用動態規劃解決問題的核心就在於填表,表填寫完畢,最優解也就找到。

最優性原理是動態規劃的基礎,最優性原理是指「多階段決策過程的最優決策序列具有這樣的性質:不論初始狀態和初始決策如何,對於前面決策所造成的某一狀態而言,其後各階段的決策序列必須構成最優策略」。

在解決問題之前,為描述方便,首先定義一些變數:vi表示第 i 個物品的價值,wi表示第 i 個物品的體積,定義v(i,j):當前揹包容量 j,前 i 個物品最佳組合對應的價值,同時揹包問題抽象化(x1,x2,…,xn,其中 xi 取0或1,表示第 i 個物品選或不選)。

1、建立模型,即求max(v1x1+v2x2+…+vnxn);

2、尋找約束條件,w1x1+w2x2+…+wnxn3、尋找遞推關係式,面對當前商品有兩種可能性:

其中v(i-1,j)表示不裝,v(i-1,j-w(i))+v(i) 表示裝了第i個商品,揹包容量減少w(i),但價值增加了v(i);

由此可以得出遞推關係式:

這裡需要解釋一下,為什麼能裝的情況下,需要這樣求解(這才是本問題的關鍵所在!):

可以這麼理解,如果要到達v(i,j)這乙個狀態有幾種方式?

肯定是兩種,第一種是第i件商品沒有裝進去,第二種是第i件商品裝進去了。沒有裝進去很好理解,就是v(i-1,j);裝進去了怎麼理解呢?如果裝進去第i件商品,那麼裝入之前是什麼狀態,肯定是v(i-1,j-w(i))。由於最優性原理(上文講到),v(i-1,j-w(i))就是前面決策造成的一種狀態,後面的決策就要構成最優策略。兩種情況進行比較,得出最優。

4、填表,首先初始化邊界條件,v(0,j)=v(i,0)=0;

然後一行一行的填表:

所以填完表如下圖:

5、**填完,最優解即是v(number,capacity)=v(4,8)=10。

為了和之前的動態規劃圖可以進行對比,儘管只有4個商品,但是我們建立的陣列元素由5個。

#include

using

namespace

std;

#include

intmain

()

;

//商品的體積2、3、4、5

int v[

5] = ;

//商品的價值3、4、5、6

int ba** =

8;

//揹包大小

int dp[

5][9] = };

//動態規劃表

for (

int i =

1; i <=

4; i++)

}//動態規劃表的輸出

for (

int i =

0; i <

5; i++)

cout

<<

endl;

}return

0;

}

通過上面的方法可以求出揹包問題的最優解,但還不知道這個最優解由哪些商品組成,故要根據最優解回溯找出解的組成,根據填表的原理可以有如下的尋解方式:

就拿上面的例子來說吧:

揹包問題最終版詳細**實現如下:

#include

using

namespace

std;

#include

int w[

5] = ;

//商品的體積2、3、4、5

int v[

5] = ;

//商品的價值3、4、5、6

int ba** =

8;

//揹包大小

int dp[

5][9] = };

//動態規劃表

int item[

5];

//最優解情況

void

findmax

() }}

void

findwhat

(int i, int j)

else

if (j - w[i] >=

0 && dp[i][j] == dp[i -

1][j - w[i]] + v[i]) }}

void

print

()

cout

<<

endl;

}cout

<<

endl;

for (

int i =

0; i <

5; i++)

//最優解輸出

cout

<< item[i] <<

' ';

cout

<<

endl;

}int

main

()

動態規劃 01揹包問題(通俗易懂,超基礎講解)

問題描述 有n個物品,它們有各自的體積和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?為方便講解和理解,下面講述的例子均先用具體的數字代入,即 eg number 4,capacity 8 i 物品編號 1 2 3 4 w 體積 2 3 4 5 v 價值 3 4 5 6 總體思...

動態規劃 01揹包問題(通俗易懂,超基礎講解)

問題描述 有n個物品,它們有各自的體積和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?為方便講解和理解,下面講述的例子均先用具體的數字代入,即 eg number 4,capacity 8 i 物品編號 1 2 3 4 w 體積 2 3 4 5 v 價值 3 4 5 6 總體思...

動態規劃 01揹包問題(通俗易懂,超基礎講解)

我只是來單純學習怎麼寫部落格的,嘿嘿 有n個物品,它們有各自的體積和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?為方便講解和理解,下面講述的例子均先用具體的數字代入,即 eg number 4,capacity 8 i 物品編號 12 34w 體積 23 45v 價值 34 ...