常見的揹包問題 01揹包和完全揹包

2021-10-06 21:58:17 字數 3352 閱讀 3249

有 n 件物品和容量為 m 的揹包,給出 n 件物品的重量 w[i] 以及價值 c[i] ,求解讓裝入揹包的物品重量不超過揹包容量且價值最大,每個物品只能選擇一次 。

暴力解法:暴力列舉每件物品要不要放入揹包,時間複雜度o(2^n),顯然是不能接受的,而使用 dp 可以將時間複雜度變成o(nm)

動態規劃:用dp[i][j]表示,前 i 件物品放入容量為 j 的揹包中所能獲得的最大價值,很明顯最終的dp[n][m]即為所求的結果,那麼怎麼求解 dp[i][j] 呢?

不放第 i 件物品,問題轉換為前 i - 1 件物品放入容量為 j 的揹包中所能獲得的最大價值,即 dp[i][j] = dp[i - 1][j] 。

放第 i 件物品,問題轉換為前 i - 1 件物品放入容量為 j - w[i] 的揹包中所能獲得的最大價值,即 dp[i][j] = dp[i - 1][j - w[i]] 。

要求最大價值,則 dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i])

求出揹包中最終裝的物品。

#include

#include

#include

using

namespace std;

const

int max_n =

1e3;

const

int max_m =

1e4;

int dp[max_n]

[max_m]

;int w[max_n]

;int v[max_n]

;vector<

int> choice;

int n, m;

intmain()

for(

int i =

1; i <= n;

++i)

//0-1揹包問題,對於每乙個物品

//用dp陣列中每一項dp【j】表示迴圈中的前i件物品,在容量為j的揹包中的最大價值

//用雙層迴圈,構建乙個前i件物品、容量0-m的表,最終表的右下角就是問題的答案

//可以為了節省空間,省略了二維陣列的行,因為每一次多乙個物品之後,答案只會受前一行影響

//先將邊界,0件物品時候的價值設為0,因為要求所選擇的物品,用二維陣列

for(

int i =

0; i <= m;

++i)

for(

int i =

0; i <= n;

++i)

//迴圈構建表

//1.當前揹包容量不夠放該物品,不放

//2.當前容量夠放該物品,看放不放的價值大小

//放的話,用揹包容量減去該物品重量,回到前dp[i-1][j-w[i]] + v[i]

//比較放與不放的價值大小,選擇大的價值的更新dp[i][j]

for(

int i =

1; i <= n;

++i)

}printf

("0 - 1 package\n");

printf

("the max value : %d\n"

, dp[n]

[m])

;//列舉選擇的每個物品

//1.先看該物品是不是被選擇了,只需要看dp[i-1][j] == dp[i][j]

//2.再退到該物品選擇前的物品的dp值處

int j = m;

for(

int i = n; i >0;

--i)

}for

(int i = choice.

size()

-1; i >=0;

--i)

return0;

}

有 n 件物品和容量為 m 的揹包,給出 n 件物品的重量 w[i] 以及價值 c[i] ,求解讓裝入揹包的物品重量不超過揹包容量且價值最大,每個物品可以重複選擇 。

下面思路與 01 揹包問題相似,僅在放第i件物品處存在差異。

不放第 i 件物品,問題轉換為前 i - 1 件物品放入容量為 j 的揹包中所能獲得的最大價值,即 dp[i][j] = dp[i - 1][j] 。

放第 i 件物品,問題轉換為前 i 件物品放入容量為 j - w[i] 的揹包中所能獲得的最大價值,即 dp[i][j] = dp[i][j - w[i]] 。

要求最大價值,則 dp[i][j] = max(dp[i - 1][j],dp[i][j - w[i]] + v[i])

求出揹包中最終裝的物品。

#include

#include

#include

using

namespace std;

const

int max_n =

1e3;

const

int max_m =

1e4;

int dp[max_n]

[max_m]

;int w[max_n]

;int v[max_n]

;vector<

int> choice;

int n, m;

intmain()

for(

int i =

1; i <= n;

++i)

//與0-1揹包不同的是,每個物品可以任意多次,當選擇第i件物品,dp[i][j] = dp[i][j - w[i]] + c[i]

for(

int i =

1; i <= n;

++i)

}printf

("\nentire package\n");

printf

("the max value : %d\n"

, dp[n]

[m])

; j = m;

for(

int i = n; i >0;

--i)

}for

(int i = choice.

size()

-1; i >=0;

--i)

return0;

}

上面揹包問題求解在空間上還可以優化,因為每次的第 i 行只與第 i - 1 行的資料有關,可以去掉dp陣列的第一維度,但是這樣揹包中選擇的物品的序號就不能得到了。

揹包問題(0 1揹包 完全揹包)

0 1揹包 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。重要的點在於 每種物品僅有一件,可以選擇放 不放子問題 f i v 表示前i件物品恰好放入乙個 容量為v 的揹包可以獲得的最大價值。狀態轉移方程 遞推式 f i v max 考...

揹包問題 0 1揹包 完全揹包和多重揹包

參考自 以下 中的w是每個物品的重量,v是每個物品的價值 w 0 list map int input split v 0 list map int input split top int input n len w d 0 top 1 for in range n 1 for i in range...

0 1揹包和完全揹包問題

有乙個容量為 n 的揹包,要用這個揹包裝下物品的價值最大,這些物品有兩個屬性 體積 w 和價值 v。定義乙個二維陣列 dp 儲存最大價值,其中 dp i j 表示前 i 件物品體積不超過 j 的情況下能達到的最大價值,每件物品只能被新增一次。設第 i 件物品體積為 w,價值為 v,根據第 i 件物品...