- 问题描述
设计动态规划算法求解0-1背包问题,要求运行时间为 O(nW) , n 为商品数,W 是小偷能放进背包的最大商品总重量。0-1背包问题用公式表示为:
maximize∑i=1nvixisubjectto∑i=1nwixi≤Wxi∈{0,1}
其中 vi 是商品的价值, wi 是商品的重量, W 是背包的容量。 - 一个递归解
假设V[i,j] :总重量不超过 j 的前提下,前i 种商品总价值的最大值。显然,当 i 或j 有一个为0,那么 V[i,j]=0 。当 i≠0 且 j≠0 时, V[i,j] 的求解可以由它的子问题给出:①若 j≥w[i] ,则求解 V[i,j] 时可以选第 i 件商品对应的最大价值为v[i]+V[i−1,j−w[i]] (此时的最大值取决于在总重量不超过 j−w[i] 的前提下,前 i−1 种商品总价值的最大值。);也可以不选择第 i 件商品,对应的最大价值为V[i−1,j] (此时的最大值即是在总重量不超过 j 的前提下,前i−1 种商品总价值的最大值。)。②若 j<w[i] ,不能选择第 i 件商品,此时所选商品的最大价值即在总重量不超过j 的前提下,前 i−1 种商品总价值的最大值 V[i−1,j] 。综上可得如下递归式:
V[i,j]=⎧⎩⎨⎪⎪0初始条件max{V[i−1,j],v[i]+V[i−1,j−w[i]]}若j≥w[i]V[i−1,j]若j<w[i] - 求解商品的最大价值
为了跟踪所选的商品,用 B[i,j] 表示在 j 的限制下从前i 件商品中构造的最优解是否含有商品 i <script type="math/tex" id="MathJax-Element-2358">i</script>。
设计算法的伪代码如下:
KNAPSACK-BST(v,w)
for i=0 to n
V[i,0]=0
for j=1 to W
V[0,j]=0
for i=1 to n
for j=1 to W
if j-w[i]>=0
if V[i-1,j]>(v[i]+V[i-1,j-w[i]])
V[i,j]=V[i-1,j]
else
V[i,j]=v[i]+V[i-1,j-w[i]]
B[i,j]=1
else
V[i,j]=V[i-1,j]
return V[n,W]
- 构造最优解
PRINT-KNAPSACK(i,j)
if i=0 or j=0
return
if B[i,j]==1
print "Item" i
PRINT-KNAPSACK(i-1,j-w[i])
else
PRINT-KNAPSACK(i-1,j)
- C++实现
#include<iostream>
#include<string>
#include<algorithm>
#define NUM 50
#define INT 65536
using namespace std;
int W;
int v[NUM];
int w[NUM];
int V[NUM][NUM];
int B[NUM][NUM];
int KNAPSACK_BST(int n)
{
for (int i = 0; i <= n; i++)
V[i][0] = 0;
for (int j = 1; j <= W; j++)
V[0][j] = 0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= W; j++){
if (j - w[i] >= 0){
if (V[i - 1][j] > (v[i] + V[i - 1][j - w[i]]))
V[i][j] = V[i - 1][j];
else{
V[i][j] = v[i] + V[i - 1][j - w[i]];
B[i][j] = 1;
}
}
else
V[i][j] = V[i - 1][j];
}
}
return V[n][W];
}
void PRINT_KNAPSACK(int i, int j)
{
if (i == 0 || j == 0)
return;
if (B[i][j] == 1){
cout << "Item" << i << " ";
PRINT_KNAPSACK(i - 1, j - w[i]);
}
else
PRINT_KNAPSACK(i - 1, j);
}
void main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> v[i];
for (int j = 1; j <= n; j++)
cin >> w[j];
cin >> W;
cout << KNAPSACK_BST(n) << endl;
PRINT_KNAPSACK(n, W);
cout << endl;
}
输入样例
i | 1 | 2 | 3 |
v | 60 | 100 | 120 |
w | 10 | 20 | 30 |
W=3
输出结果