01揹包和動態規劃

2022-04-07 07:37:39 字數 2853 閱讀 5674

做了一段時間noi,做到動態規劃看了幾天演算法書籍。還是沒有深入,學了基本的動態規劃,稍有一點體會,記錄到這裡。

揹包是這樣一類問題:在限定總質量前提下,從若干質量\**對中,取哪些能使得**最大。

動態規劃是一種思想,簡單的說,動態規劃思想就是充分利用對子問題的計算結果來遞推父問題結果。所以,動態規劃具有較高的效率,省去了一些不必要的計算。這裡主要關心表和遞推關係,其實這兩者是同乙個東西,根據記錄表來推得父問題的解,找到遞推關係要依賴表記錄子問題的解。不同的問題有不同的構建方式,所以我個人覺得,初學時沒有必要看了理論然後直接去寫**,可以看一下其他人是如何寫的**。邊除錯**邊理解思路效率更高,但這還不是自己的東西,需要一定的練習。動態規劃是一種思想,但解決不同型別(特點)的問題時有不同的突破口,這也導致即使都用動態規劃不同問題的解決**差異也較大,同樣道理,相同型別的問題**的框架結構是一樣的,掌握一類問題的分析方法和編碼框架都是必要的,兩者相輔相成,就像我們要輸出乙個陣列的全部元素,大家都會馬上拿來for while這樣的語句來用。

現在來看揹包問題是怎麼利用記錄表來高效解決問題的,這裡有一組範例資料:

471

2315

10411

其中,第一行是質量\**對個數和允許最大質量,記為n=4,w=7。後續4行前面是質量,後面是**,可以用兩個陣列記錄也可以用結構。顯而易見,選擇物品1和4可以達到價值13(質量5)。現在來看一下解決這個問題的記錄表:

m w  oid

0 1 2 3 4 5 6 7

0 0 0 0 0 0 0 0 0

1 2 102

2222

223 1 202

2233

335 10 302

22310

1212

4 11 402

221113

1313

表是從左到右填寫完一行再從左到右填寫下一行。其中綠色的行是選擇物品的範圍最大下標oid(如oid=2表示從編號為1、2的兩個物品中選擇);而紅色的行是當前允許最大質量curw——這就是動態規劃解決揹包問題的思路,從0容量揹包開始,讓後是1一直遞推到最大揹包容量;表內資料部分就是記錄值——table[oid][curw]記錄了在前oid個物品中取若干個裝入curw大小的揹包能裝入的最大價值。所以,無論01揹包、完全揹包、部分揹包或同類問題用動態規劃都是乙個**框架(尤其是01和完全,**就差2點點)。現在我們思考這樣幾個問題:

1、揹包問題對於任何乙個物品來講,只有兩種狀態:取、不取。那麼,這兩種狀態的編碼怎麼寫?

其實這個問題相對比較簡單,只要當前揹包質量不達到當前物品質量,那就無需裝入;達到了就嘗試裝入,即:

if(curwelse

2、如何嘗試裝入?

還記得上面所說的curw大小的揹包能裝入的最大價值嗎?這兩者也是同乙個問題,為了保證curw儲存最大價值,我們需要嘗試把當前物品放入揹包。那麼如何得到放入揹包之前的最大價值呢?table[oid][curw-warr[oid]]就是了,因為我們已經記錄了從0到curw的任何乙個質量的最大價值(這也是從curw從0遍歷到maxw的原因,也是優化的突破口),所以這個值就是沒有放入當前物品時的最大價值。不要擔心curw-warr[oid]的大小,我們討論的就是curw>=warr[oid]的情況。

現在計算物品放入揹包之後的價值:table[oid][curw-warr[oid]]+varr[oid]。這是一種嘗試,通過嘗試放入當前物品,我們知道放入之後的最大價值,但是這個價值不一定比不放的時候大。所以,現在我們需要在放入這個物品之後的價值table[oid][curw-warr[oid]]+varr[oid]和不嘗試放入這個物品時的最大價值table[oid][curw]中找到最大的那個。那麼把**放在下面更便於瀏覽:

int

dp()

else

printf(

"% 2d

",table[oid+1

][curw]);

}cout

<}

return

table[n][w];

}

根據上面的分析,顯然需要從0容量揹包開始遞推,而取物品時會用到不取任何物品時的值(「拿走一部分那裡」),所以內外迴圈這裡都從0開始。當然,如果你修改**不使用oid+1而直接使用oid,將會有一些不同。但無論如何,用於遞推的基礎資料——table表的一部分都需要初始化:

for(i=0;i<=n;i++) table[0][i]=0;

完整**如下:

#include#include

using

namespace

std;

intn,w;

int warr[100]=;

int varr[100]=;

int table[100][100

];

intdp()

else

printf(

"% 2d

",table[oid+1

][curw]);

}cout

<}

return

table[n][w];

}int

main()

可能對於table[oid][curw-warr[oid]]的解釋有人還不理解。現在,我們不從warr[oid]質量的物體前的情況出發,我們來看空揹包先放入warr[oid]的物品之後還能放的物品的最大值:想象可容納curw質量的揹包有兩個口袋,其中乙個正好裝入warr[oid]質量。想象中,請稍候…………那麼,整個揹包能裝的最大價值是多少取決於另乙個口袋的能裝的最大價值是多少。table[oid][curw-warr[oid]]就是另乙個口袋能裝下的最大價值。

動態規劃 01揹包

最優二叉查詢樹.cpp 定義控制台應用程式的入口點。01揹包問題。include stdafx.h include include define n 3 the number of real node define m 10 using namespace std int tmain int arg...

01揹包動態規劃

0 1揹包 問題描述 乙個旅行者有乙個最多能用 m公斤的揹包,現在有 n件物品,它們的重量 分別是w1,w2 wn,它們的價值分別為 c1,c2,cn.若每種物品只有一 件求旅行者能獲得最大總價值。輸入格式 w 第一行 兩個整數,m 揹包容量,m 200 和n 物品數量,n 30 w第2.n 1 行...

0 1揹包(動態規劃)

題意 有n件物品和乙個容量為v的揹包。第i件物品的體積是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。基本思路 這是最基礎的揹包問題,特點是 每種物品僅有一件,可以選擇放或不放。用子問題定義狀態 即f i v 表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。則其狀態轉移方程...