揹包問題總結

2022-05-09 02:54:09 字數 2928 閱讀 8029

**:揹包九講

有揹包容量為v,n個物品,每個重量為w[i],價值為v[i],每個物品僅有一件,要使得揹包價值最大怎麼裝物品?

定義dp陣列含義:dp[i][j]表示考慮前i個物品在揹包容量恰為j的情況下達到的最大價值。

狀態轉移方程:

f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

解釋:針對第i個物品有兩種選擇,一是放進揹包,一是不放進揹包。max中的第一項就是不放進揹包,那麼就轉換為考慮前i-1件物品放進容量為j的揹包;第二項是放進揹包,問題轉化為前i-1件物品放入容量為j-w[i]的揹包,此時的最大價值是再加上當前的物品的價值。

使用滾動陣列的思想:

​for (int i = 1; i <= n; i++)//遍歷物品

for (int j = v; j >= 0; j--)//遍歷容量

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

外層遍歷物品,內層要從大到小遍歷,因為物品最多只能取一次。(完全揹包問題中是從小到大遍歷容量,因為可以取無限次。)

只要數量有限制都只能從大到小遍歷,其實從原始公式中看的更明顯,從大到小只保證使用的是i-1的計算結果。

總結:如果容量從小到大遍歷,那麼就會重複計算物品,使用的是之前計算的結果,針對完全揹包問題;那麼針對01揹包問題,就需要從後往前,就不會重複計算包了。

力扣例題:416. 分割等和子集

有揹包容量為v,n個物品,每個重量為w[i],價值為v[i],每個物品有無數件,要使得揹包價值最大怎麼裝物品?

dp陣列含義和上面相同,按照每個物品可取數量可以這麼寫,

f[i][j]=max(f[i−1][j−k∗w[i]]+k∗v[i])∣0

<=k∗w[i]<=j

但是不好解。

for (int i = 1; i <= n; i++)//遍歷物品

for (int j = w[i]; j <= v; j++)//遍歷容量

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

遍歷物品,但揹包容量是從小到大的,因為物品可以無限次使用。

兩層for迴圈可以替換?

舉例:322. 零錢兌換

for(int i=1;i<=amount;i++)

}for(int i=0;i)

}

377. 組合總和 ⅳ,完全揹包問題,求組合數,結果可以重複,所以是對物品的排列,需要先遍歷容量,再遍歷物品。

* 1.0-1揹包問題,外層遍歷物品,內層從大到小遍歷容量;(因為只能用一次)

* 完全揹包問題,外層便利物品,內層從小到大遍歷容量。(能用多次)

70. 爬樓梯,如果本題用揹包思想來做,因為是排列問題,不是組合問題,所以需要遍歷容量,如果遍歷物品的話,那麼物品的順序是定的,就出現方法數變少的錯誤。

!!!錯誤的**!!!

class

solution ;

vector

dp(n+1,0

); dp[

0]=1

;

for(int i=0;i)

}return

dp[n];

}};

//

正確的**:

class

solution3 ;

vector

dp(n+1,0

); dp[

0]=1

;

for(int i=1;i<=n;i++)

}return

dp[n];

}};

每件物品多了個數量限制。

//還沒有做過這樣得的題目。

有的可以取0-1次,有的可以取無限次,有的能取k次。

那麼針對0-1和完全可以分開求解:

p[i]:每個物品的件數,0代表無窮個

for (int i = 1; i <= n; i++)//

遍歷物品

if (p[i] == 0)//

完全揹包問題

for (int j = w[i]; j <= v; j++)//

從小到大遍歷

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

else

for (int k = 1; k <= p[i]; k++)//

如果p[i]是1,就是0-1揹包問題,否則是多重揹包問題

for (int j = v; j >= w[i]; j--)

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

//還沒有做過這樣的題目,希望做的時候能想到解法。

現在物品有兩種重量,兩種價值,當然也有兩個揹包,也就是有兩個限制,那麼就再多加一維狀態:

定義dp陣列含義:dp[i][j][k]表示考慮前i件物品,揹包容量分別為j和k時能達到的最大價值。

狀態轉移:

max(f[i−1][j][k],f[i−1][j−w[i]][k−g[i]]+v[i])//不放、放

那麼此時就需要從大到小遍歷:

for (int i = 1; i <= n; i++)

for (int j = v; j >= w[i]; j--)//兩層均需要從大到小遍歷

for (int k = t; k >= g[i]; k--)

f[j][k] = max(f[j][k], f[j - w[i]][k - g[i]] + v[i]);

時間複雜度就是三層for迴圈乘積了,空間複雜度降成了二維。

題目:474. 一和零

揹包問題 01揹包總結

寫這篇部落格的原因是因為自己初學揹包的時候覺得好玄學。只是知道怎麼寫,但是具體是為什麼覺得很玄妙。在此其實希望和我一樣的小白萌新早點明白其中的原理,其實原理很簡單,只要懂了這個圖,我想01揹包就不成問題了。首先要明確這張表是至底向上,從左到右生成的。關於01揹包的題目暫時整理了一點。1.簡單01揹包...

揹包問題總結

標籤 acm dp 揹包 n 物品,乙個揹包,每個物品價值wi 體積vi 揹包容量 c 求最大價值 對於物品 i可選可不選 fi j fi 1 j vi j 0 fi j max c j vi 給定 n 種物品和乙個揹包。第 i種物品的價值是 wi 其體積為vi 揹包的容量為 c 同一種物品的數量無...

揹包問題總結

揹包問題主要是分為三種 0 1揹包,完全揹包,多重揹包 1 0 1揹包 定義 何謂0 1揹包,可以這樣想,那裡有一堆值錢的東西,每一樣東西只有一件,他們的價值和體積都不一樣,現在要你從這n件裡面挑選一些放到乙個容量一定的揹包裡面,使得你的揹包裡的東西總價值最大。對於這些東西的每一件,你可以選擇放進你...