问题要求:
有一个背包,它的容量为C(Capacity),现在有n中不同的物品,编号为0...n-1,其中每一件物品的重量为w(i),价值为v(i)。问可以向这个背包中盛放哪些物品,使得在不超过背包容量的基础上,物品的总价值最大。
递归解题代码:
class Knapsack01 {
private:
vector<vector<int>> memo;
// 用 [0...index] 的物品, 填充溶剂为c的背包的最大价值
int bestValue(const vector<int>& w, const vector<int>& v, int index, int c) {
if (index < 0 || c <= 0)
return 0;
if (memo[index][c] != -1)
return memo[index][c];
int res = bestValue(w, v, index - 1, c);
if (c >= w[index])
res = max(res, v[index] + bestValue(w, v, index - 1, c - w[index]));
memo[index][c] = res;
return res;
}
public:
int knapsack01(const vector<int>& w, const vector<int>& v, int C) {
int n = w.size();
memo = vector<vector<int>>(n, vector<int>(C + 1, -1));
return bestValue(w, v, n - 1, C);
}
};
动态规划代码逻辑:
class Knapsack01 {
public:
int knapsack01(const vector<int>& w, const vector<int>& v, int C) {
assert(w.size() != v.size());
int n = w.size();
if (n == 0)
return 0;
vector<vector<int>> memo(n, vector<int>(C + 1, -1));
for (int j = 0; j <= C; ++j) {
memo[0][j] = (j >= w[0] ? v[0] : 0);
}
for (int i = 1; i < n; ++i) {
for (int j = 0; j <= C; ++j) {
memo[i][j] = memo[i - 1][j];
if (j >= w[i])
memo[i][j] = max(memo[i][j], v[i] + memo[i - 1][j - w[i]]);
}
}
return memo[n - 1][C];
}
};
进一步的优化:
class Knapsack01 {
public:
int knapsack01(const vector<int> &w, const vector<int> &v, int C) {
assert(w.size() != v.size());
int n = w.size();
if (n == 0)
return 0;
vector<vector<int>> memo(2, vector<int>(C + 1, -1));
for (int j = 0; j <= C; ++j) {
memo[0][j] = (j >= w[0] ? v[0] : 0);
}
for (int i = 1; i < n; ++i) {
for (int j = 0; j <= C; ++j) {
memo[i % 2][j] = memo[(i - 1) % 2][j];
if (j >= w[i])
memo[i % 2][j] = max(memo[i % 2][j], v[i] + memo[(i - 1) % 2][j - w[i]]);
}
}
return memo[(n - 1) % 2][C];
}
};
再次优化
class Knapsack01 {
public:
int knapsack01(const vector<int> &w, const vector<int> &v, int C) {
assert(w.size() != v.size());
int n = w.size();
if (n == 0)
return 0;
vector<int> memo(C + 1, -1);
for (int j = 0; j <= C; ++j) {
memo[j] = (j >= w[0] ? v[0] : 0);
}
for (int i = 1; i < n; ++i) {
for (int j = C; j >= w[i]; j--) {
memo[j] = max(memo[j], v[i] + memo[j - w[i]]);
}
}
return memo[C];
}
};