1.問題描述
有n個物品,第i個物品的體積和價值分別爲w[i]、v[i](1<= i <=n),現有一個容量爲c的揹包,將這些物品選擇裝入該揹包,如何選擇使得包裏的物品價值總和最大。
2.問題分析
定義函數f[i][w]表示從前i件物品中選擇放入容量爲w的揹包能裝下的物品最大價值,我們所要求的就是f[n][c]。以n爲例,有兩種情況:
a. 如果w[n]>c,那麼n就不能選中,即f[n][c] = f[n-1][c]
b. 如果w[n] <= c, 那麼n有可能選中也可能沒有選中,依據就是判斷選中和不選中的結果哪個大酒根據那一個,即比較f[n-1][c-w[n]]+v[n]和f[n-1][c]
3.編寫代碼
在解決該問題時因爲每一個f都依賴上一個結果,所以需要從最小的f開始向上計算,得到結果,易得f[0][i] f[i][0]都是0,我們需要從0開始計算出所有f[][]
//i表示從前i項選擇,j表示容量
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= c; j++) {
if (w[i] > j) {
f[i][j] = f[i - 1][j];
} else {
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
}
}
}
完整代碼如下
#include <iostream>
#include <cmath>
using namespace std;
int knapsack(int n, int c, int v[], int w[]) {
int f[1001][1001] = {0};
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= c; j++) {
if (w[i] > j) {
f[i][j] = f[i - 1][j];
} else {
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
}
}
}
return f[n][c];
}
int main () {
int n, v[1001];
int c, w[1001];
while (cin >> n >> c) {
for (int i = 1; i <= n; i++) {
cin >> w[i] >> v[i];
}
cout << knapsack(n, c, v, w) << endl;
}
return 0;
}
如果想得到選擇的具體情況可以通過f[i][c]-f[i-1][c]的值判斷,如果f[i][c]>f[i-1][c],那麼就是選取了第i個,接下來就要判斷f[i - 1][c - w[i]] 和f[i - 2][c - w[i]],注意i從大到小判斷,遇到被選中的,加下來的判斷就要減去這個重量
int w = totalWeight;
for (int i = n; i != 0; i--) {
if (f[i][w] > f[i - 1][w]) {
cout << i << " ";
w -= w[i];
}
}