0-1背包问题解法
问题提出
背包问题。给定n个重量为 $w_{1},w_{2},\ldots,w_{n}$,价值为$v_{1},v_{2},\ldots,v_{n}$的物品和一个承重为W的背包,求将这些物品中的 某些装入背包中,在不超出重量W的情况下,价值最高的装法。
解法1——穷举法
算法描述
通过递归完成对所有解的遍历,记录遍历过程中的最优解
算法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <iostream>
using namespace std;
const int N = 4; const int W = 10;
typedef struct commodity { int weight; int value;
int flag; } commodity;
commodity goods[N] = {{7, 42, 0}, {3, 12, 0}, {4, 40, 0}, {5, 25, 0}}; int r[N + 1] = {0}; int sum_w = 0, sum_v = 0; int ans = 0;
int record(int sum_v) { int count = 0; r[0] = sum_v; for (int i = 0; i < N; i++) { if (goods[i].flag) r[++count] = i + 1; } return count; } void knaps(int x) { if (sum_w > W) return; if (sum_v > r[0]) ans = record(sum_v); for (int i = x; i < N; i++) { sum_v += goods[i].value; sum_w += goods[i].weight; goods[i].flag = 1; knaps(i + 1); sum_v -= goods[i].value; sum_w -= goods[i].weight; goods[i].flag = 0; r[i] = 0; } }
int main() { knaps(0); cout << "有" << ans << "个物品被选中了" << endl; cout << "max value is:" << r[0] << endl; return 0; }
|
时间复杂度分析
可得:
运行结果

解法2——动态规划
计算模型
定义价值函数 $P(i,W)$:在 $i$件物品中选择总重量不超过 $W$的物品装入背包,记此时使得背包总价值最大的取值为:$m(i,W),\quad 1 \leq i \leq n, \quad 1 \leq W \leq C$
对于第 $i$个物品,存在两种情况:
- 不选,背包容量仍然为 $W$,问题变为 $P=(i-1,W)$
- 选,背包容量变小,问题变为 $P(i-1,W-w_{i})$
则,$m(i,W) = \max{\{ m(i-1,W),m(i-1,W-w_{i})+v_{i} \}}$
算法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include <iostream>
using namespace std;
const int N = 4; const int W = 10;
int m[N + 1][W + 1];
int max(int a, int b) { return a > b ? a : b; }
void DP_Knapsac(int w[], int v[]) { int i, weight; for (i = 0; i <= W; i++) m[0][i] = 0; for (i = 1; i <= N; i++) m[i][0] = 0; for (i = 1; i <= N; i++) { for (weight = 1; weight <= W; weight++) { if (w[i] > weight) m[i][weight] = m[i - 1][weight]; else m[i][weight] = max(m[i - 1][weight], m[i - 1][weight - w[i]] + v[i]); } } }
void Selected_Item(int w[], int v[]) {
int remainspace = W; for (int i = N; i >= 1; i--) { if (remainspace >= w[i]) { if ((m[i][remainspace] - m[i - 1][remainspace - w[i]] == v[i])) { cout << "item of " << w[i] << "kg" << " is selected" << endl; remainspace = remainspace - w[i]; } } } }
int main() { int w[5] = {0, 7, 3, 4, 5}; int v[5] = {0, 42, 12, 40, 25}; DP_Knapsac(w, v); Selected_Item(w, v); return 0; }
|
时间复杂度分析
求解函数DP_Knapsac的主要内容为两层for循环,则:
其中,N为物体总件数,W为背包总容量
运行结果
