dp入門與兩個基礎的揹包問題

2021-08-01 16:16:11 字數 1351 閱讀 6988

引子:

第乙個問題:現在有3種硬幣,1角錢,2角錢,3角錢,那麼問題來了湊出n角錢最少需要多少硬幣。

這個問題可以用貪心法解決。如果n比3大,那麼一直取3就好了。最後少的要麼是2,要麼是1,所以答案是n/3+(n%3)?1:0;

第二個問題:現在有3種硬幣,2角錢,3角錢,5角錢,那麼問題來了湊出n角錢最少需要多少硬幣。

如果n為16的話,一直取5那麼最後剩1,就就不行了。

這時候就要用到動態規劃。

01揹包

01揹包問題描述:現在有n個物品,人現在有乙個容量為m的揹包,每個物品有價值vi和重量wi,那麼問題來了,在總重量不超過m的情況下使得價值最大,請問該怎麼選?

這是最基礎的問題,特點是對於每一種物體僅有乙個,只存在放或者不放兩種情況。

我們設p[i][j]表示前i個物體放入乙個容量為j的揹包時的最大價值。那麼對於p[i-1]來說,我們可以看出就是乙個取第i個和不取第i個的區別。那麼就可以列出式子

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

所以我們可以列出式子

for(int i=0;ifor(int j=m;j>=w[i];j--)

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

至於為什麼第二重迴圈要從m迴圈到w[i]呢,其實在這裡從m到w[i]或者從w[i]到m是無所謂的。

但是,如果只用一維陣列來存結果,那麼第二重迴圈就必須從m減到w[i]了。因為一維陣列預設用到的前乙個p[i-1][j]的值,我們必須保證用到的是上一層迴圈留下來的資料而不是這個i值留下來的新的資料。

for(int i=0;ifor(int j=m;j>=w[i];j--)

p[j]=max([j],p[j-w[i]]+v[i]);

是不是簡單多了?

完全揹包

完全揹包問題是另外一種揹包問題,還是原來的m,w[i],v[i],但是這時候每種可以取無數多個。

那麼最直接的想法,f[i-1][j]=max,0

然而這個演算法複雜度是o(n^3)的,太恐怖了,簡直不堪入目,不到萬不得已不能用的。

那麼怎麼辦呢?對於f[i-1][j]來說,再用取或者不取的思路來說,應該是f[i][j]=max(f[i-1][j],f[i][j-w[i]]+v[i])

這時候我們可以想一想,上面01揹包的第二重迴圈為什麼要從m到w[i],就是為了保證每種只取一次。現在既然每種可以取無限次,那麼就沒必要從m開始迴圈了,從0開始恰好就滿足了完全揹包的條件。

for(int i=0;ifor(int j=v[i];j<=v;j++)

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

那麼dp[n][m]就是答案了。

DP入門, 0 1揹包問題

hloj 1006 0 1揹包問題 hdu 2602 bone collector類似,但要注意輸入順序,問題規模,最重要的是重量為0的骨頭居然也有價值的!includeusing namespace std define n 401 define m 1501 int f n m 下標從1開始用 ...

Dp基礎 簡單揹包問題

揹包問題大意 給你乙個揹包有一定的容量,再給你一下些物品,物品有自己的體積和價值,請你選擇價值和最大的一些物品 最體積不超過揹包的容量 揹包問題思路 逐漸放每乙個物品,找到當前體積的最大價值。揹包問題的主要 for i 1 i n i 逐漸放乙個物品 for j m j w i j 列舉揹包放下這個...

動態規劃的兩個經典問題 01揹包

學動態規劃要從經典問題開始 by lrj 答應了小q要寫這個的.哎.先說那個什麼01揹包.為什麼叫揹包呢?因為這些問題的原型是說有很多東西,每個東西都有體積,也有價值,你要去春遊,要選一些東西放到揹包裡.問題是要怎麼選才能在總體積不超過揹包的體積的前提下,讓總價值最大.為什麼是0 1呢?因為每種東西...