王道機試 第十二章 動態規劃 12.5 揹包問題
1、0-1揹包
0-1揹包的關鍵特點:每種物品至多選一次),要麼選要麼不選(0/1次)。
例題12.7 點菜問題(北京大學複試上機題)
- 注意事項
- 揹包數組的範圍——和容量C相關,定義maxm=C+5
- 內層循環倒序
原因:
0-1揹包問題的原始DP方程爲。由此可知,在第輪更新時,使用的是第輪的的數值。即:在第輪必須先更新,然後才輪到更新,因此必須讓倒序遞減循環,以保障更新順序。
0-1揹包問題的C++核心代碼如下:
- 初始化:
const int maxm = 1005; // 揹包容量+5
int dp[maxm]; // dp數組
memset(dp, 0, sizeof(dp)); // 初始值
- 遞推(內層循環倒序):
for (int i = 1; i <= n; i++){
for (int j = C; j >= w[i]; j--){
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
- 結果輸出
cout << dp[C] << endl; // C爲揹包容量
本問題的完整C++代碼如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 105;
const int maxm = 1005;
int dp[maxm];
int w[maxn], v[maxn]; // 重量,價值
int main()
{
int C, n;
while (cin >> C >> n){
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++){
cin >> w[i] >> v[i];
}
for (int i = 1; i <= n; i++){
for (int j = C; j >= w[i]; j--){
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
cout << dp[C] << endl;
}
return 0;
}