有 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 件物品...