手把手教你dp 01揹包問題(遞迴改動態規劃DP)

2021-10-25 15:30:46 字數 3359 閱讀 2802

手把手教你dp:01揹包問題(遞迴改動態規劃dp)

手把手教你dp:摘花生問題(遞迴改動態規劃dp)

手把手教你dp:藍橋杯-地宮尋寶(遞迴改動態規劃dp)

有 n 件物品和乙個容量是 v 的揹包。每件物品只能使用一次。

第 i 件物品的體積是 vi,價值是 wi。

求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。

輸出最大價值。

輸入格式

第一行兩個整數,n,v,用空格隔開,分別表示物品數量和揹包容積。

接下來有 n 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。

輸出格式

輸出乙個整數,表示最大價值。

資料範圍

0 < n,v ≤ 1000

0 < vi,wi ≤ 1000

輸入樣例

4 51 2

2 43 4

4 5輸出樣例:

8對於每一件物品我們都可以選擇拿或者不拿,因此可以遞迴選擇每個位置的物品拿或者不拿。

(1)當揹包剩餘容量小於當前位置物品的體積時,我們只能選擇不拿當前位置的物品

(2)當揹包剩餘容量小於或者等於當前位置物品的體積時,我們可以選擇拿當前位置物品與不拿當前位置物品

a.如果拿當前位置物品,則揹包內物品總價值相應增加,揹包容積相應減小,繼續確定下乙個位置。

b.如果不拿當前位置物品,則揹包內物品總價值和容積保持不變,繼續確定下乙個位置。

以上過程的終止條件是當前位置指向最後乙個物品的下乙個位置或者當前揹包容積為0,即為遞迴終止條件

w是代表當前揹包中物品的總價值

cur是當前物品的位置

v是當前揹包的剩餘容量

int w;

intprocess

(int cur,

int v)

return w +

max(s[cur]

.y +

process

(cur +

1, v - s[cur]

.x),

process

(cur +

1, v));

}

#include

#define x first

#define y second

using

namespace std;

typedef pair<

int,

int> pii;

const

int n=

1010

;int n, v;

pii s[n]

;int w;

intprocess

(int cur,

int v)

return w +

max(s[cur]

.y +

process

(cur +

1, v - s[cur]

.x),

process

(cur +

1, v));

}intf(

int v)

intmain()

對於乙個無後效性問題,只要寫出了遞迴版本,就可以在遞迴的基礎上改出dp,甚至不需要關注原問題,只需要關注遞迴**即可

(1)首先我們需要判斷是哪幾個變數確定了一種狀態,不難發現,上面遞迴中的cur和v可以唯一確定一種狀態,因此我們的dp表是二維的。

(2)確定cur和v的範圍,在二維表中我們以v代表行,cur代表列,顯然v的範圍[0, v],cur 的範圍是[1, n+1](n是物品的個數,我們假設物品從1~n編號,因為遞迴的終止掉條件是cur == n+1,因此cur的範圍需要包括n+1)。

(3)確定目標結果在二維表中的位置,顯然,我們的目標位置是(v, cur) = (v, 1)。

(4)根據遞迴終止條件,確定表的邊界狀態,有上述遞迴**可得,當cur = n+1時,整列全為0;當v=0時,整行全為0,因此我們的二維表的初始狀態為一行全為0,最後一列全為0。

(5)對於任意乙個位置,由上述遞迴**,推出狀態轉移方程。對於任意乙個位置(v, cur) = (i, j),如果 j 號物品的體積大於揹包容積v,則dp[i][j] = dp[i][j+1];

if

(s[cur]

.x > v)

return w +

process

(cur +

1, v)

;

如果 j 號物品的體積小於或者等於揹包容積v,則dp[i][j] = max(s[j].w + dp[i-s[j].v][j+1], dp[i][j+1])。

return w +

max(s[cur]

.y +

process

(cur +

1, v - s[cur]

.x),

process

(cur +

1, v)

);

通過上述五步分析,由於表中第一行和最後一列的值都已確定為0,因此我們只需要從第二行倒數第二列開始求解,知道求解到目標位置(v, cur) = (v, 1)。

for

(int i = n; i >=

0; i--

)}

求解完dp表,目標位置上的值就是我們的結果。

#include

#define x first

#define y second

using

namespace std;

typedef pair<

int,

int> pii;

const

int n=

1010

;int n, v, t;

pii s[n]

;int w;

int dp[n]

[n];

intmain()

} cout << dp[1]

[v]<< endl;

return0;

}

(1)dp表的維度:即狀態由幾個變數唯一確定。

(2)確定表的各個維度的取值範圍。

(3)確定目標值在dp表中的位置。

(4)根據遞迴終止條件,確定dp表的初始狀態。

(5)確定dp表中任意乙個位置的值與表中其他位置的依賴關係,即狀態轉移方程。

從遞迴到DP 01揹包問題初探

目錄 問題描述 1.純遞迴解決,容易溢位 2.記憶化搜尋法 3.由記憶化搜尋推導遞推關係,使用動態規劃法dp 備註 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。測試樣例 n 4,w 5 42 3 ...

演算法筆記 揹包DP (0 1揹包)

1.0 1揹包 參考例題 hloj416採藥 二維解法 我們設f i j 為前i個物品放進容量為j的揹包的最大價值 設體積為v i 價值為w i 我們可以列舉i 1到n 和j 1到n 不難得出狀態轉移方程 f i j max 可以知道,當第i件物品不取時,總價值為f i 1 j 取得話,總價值為前i...

手把手教你解決郵件亂碼問題

我們平時收到郵件的時候,有時候會發現有些郵件是亂碼,如同一本 天書 啥也看不懂,這是什麼原因造成的呢?歸納起來不外乎以下三種情況 一是作業系統和使用的軟體設定不同導致的 二是傳送郵件時傳送程式採用不同的編碼標準,如uu mime binhex等,而你所用的作業系統程式沒有能力將其解碼,收到的郵件像 ...