0-1背包问题是一个经典的动态规划问题,问题定义如下:有n个物品,其重量分别为W={w1, w1, w3, ... wn},其价值分别为V={v1, v2, v3, .. vn}。现在要将这N个物品放入允许的最大重量为w的包中,问怎样选择物品能使包中的物品总价值最大。
可以将背包问题划分成若干个子问题,关键在于如何对问题进行划分。现在将问题表述为在重量限制为w的情况下,求对前N个物品进行选择能得到的最大价值,即v[n, w]。对于一个物品i,求v[i, w']时有两种情况可供选择:若选中物品i,则所得的最大价值为v[i-1, w'-wi]+vi;若不选中物品i,则所得的最大价值为v[i-1, w']。选择二者之间的较大值即可求出最优解。因此,子问题可以分解成两个更小的子问题。
解决0-1背包问题的C++代码如下所示, 代码中用到了boost库中的multi_array:
0-1背包问题
1#include <iostream>
2#include <boost/multi_array.hpp>
3
4using namespace std;
5
6// 动态规划解决0-1背包问题
7void Knapsack(int weightArray[], int valueArray[], size_t length, int totalWeight)
8{
9 // 价值表
10 boost::multi_array<int, 2> valueTable(boost::extents[length + 1][totalWeight + 1]);
11 // 选择表
12 boost::multi_array<bool, 2> selectionTable(boost::extents[length + 1][totalWeight + 1]);
13 // 初始化前0个物品的最大价值为0
14 for (size_t itemIdx = 0; itemIdx <= length; ++itemIdx)
15 {
16 valueTable[itemIdx][0] = 0;
17 }
18 // 初始化允许重量为0是的最大价值为0
19 for (int weightIdx = 0; weightIdx <= totalWeight; ++weightIdx)
20 {
21 valueTable[0][weightIdx] = 0;
22 }
23
24 // 从底层开始填写价值表和选择表
25 for (size_t itemIdx = 1; itemIdx <= length; ++itemIdx)
26 {
27 for (int weightIdx = 1; weightIdx <= totalWeight; ++weightIdx)
28 {
29 // 先计算不选择当前物品时的最大价值
30 int valueUnselected = valueTable[itemIdx - 1][weightIdx];
31 // 允许的重量需大于等于当前物品的重量,否则当前物品不可选
32 if (weightIdx >= weightArray[itemIdx - 1])
33 {
34 // 计算选择当前物品时的最大价值
35 int valueSelected = valueArray[itemIdx - 1] +
36 valueTable[itemIdx - 1][weightIdx - weightArray[itemIdx - 1]];
37 // 若选择当前物品时所得到的最大价值大于不选择时的最大价值,
38 // 则选择当前物品,并进行下一次循环
39 if (valueSelected >= valueUnselected)
40 {
41 valueTable[itemIdx][weightIdx] = valueSelected;
42 selectionTable[itemIdx][weightIdx] = true;
43 continue;
44 }
45 }
46
47 // 处理不选择当前物品的情况
48 valueTable[itemIdx][weightIdx] = valueUnselected;
49 selectionTable[itemIdx][weightIdx] = false;
50 }
51 }
52
53 // 打印最大值以及被选中的物品编号
54 cout << "最大价值为:" << valueTable[length][totalWeight] << endl;
55 cout << "以下编号的物品被选中:";
56 for (size_t itemIdx = length, weightIdx = totalWeight; itemIdx > 0; --itemIdx)
57 {
58 if (selectionTable[itemIdx][weightIdx])
59 {
60 cout << itemIdx << " ";
61 weightIdx -= weightArray[itemIdx - 1];
62 }
63 }
64 cout << endl;
65}
66
67int main()
68{
69 int weights[] = {1, 2, 3, 2, 2};
70 int values[] = {8, 4, 0, 5, 3};
71 int totalWeight = 4;
72 Knapsack(weights, values, sizeof(weights) / sizeof(int), totalWeight);
73 return 0;
74}
请各位批评、指正~