题目(Description):
0-1背包问题是给定n个重量为 {w1, w2, … ,wn}、价值为 {v1, v2, … ,vn} 的物品和一个容量为 C 的背包,求这些物品中的一个最有价值的子集,并且要能够装到背包中。
要求:用动态规划法求0/1背包问题的最优解。
输入(Input):
(1)物品的总个数;
(2)背包的总容量;
(3)每个物品的重量;
(4)每个物品的价值。
输出(Output):
(1)最优解;
(2)背包中物品的最大价值。
示例(Sample):
输入(Input):
4
10
7 3 4 5
42 12 40 25
输出(Output):
(0,0,1,1)
65
分析
这是约束优化问题,可以看成一个决策过程
(
x
1
,
x
2
,
⋯
,
x
n
)
\left(x_1,x_2,\cdots,x_n\right)
(x1,x2,⋯,xn),其中
x
i
∈
{
0
,
1
}
x_i\in\{0,1\}
xi∈{0,1}。也就是说问题被分解成n步决策,每一步决策只依赖于上一步决策的结果。对
∀
x
i
∈
(
x
1
,
x
2
,
⋯
,
x
n
)
\forall x_i\in\left(x_1,x_2,\cdots,x_n\right)
∀xi∈(x1,x2,⋯,xn)的决策,都是在
(
x
1
,
x
2
,
⋯
,
x
i
−
1
)
\left(x_1,x_2,\cdots,x_{i-1}\right)
(x1,x2,⋯,xi−1)已经完成决策的情况下进行的。在对
x
i
−
1
x_{i-1}
xi−1决策之后,在决策x_i时,问题处于下列两种状态之一:
1.背包容量不足以装入物品
i
i
i,
x
i
=
0
x_i=0
xi=0,背包价值不变;
2.背包容量允许装入物品
i
i
i,
x
i
=
1
x_i=1
xi=1,背包价值增加
v
i
v_i
vi。
这两种情况下背包价值的最大者应该是对
x
i
x_i
xi决策后的价值。
举个例子:
构造动态规划表格
编程实现
#include <iostream>
using namespace std;
int KnapSack(int n, int C,int w[], int v[]) {
int i,j;
int V[20][200];
for(i=0; i<=n; i++)
V[i][0]=0;
for(j=0; j<=C; j++)
V[0][j]=0;
for(i=1; i<=n; i++) {
for(j=1;j<=C;j++)
if(j<w[i])
V[i][j] = V[i-1][j];
else {
//V[i][j]=max(V[i-1][j],V[i-1][j-w[i]]+v[i]);
if (V[i-1][j]<V[i-1][j-w[i]]+v[i])
V[i][j] = V[i-1][j-w[i]]+v[i];
else
V[i][j] = V[i-1][j];
}
cout << endl;
}
//打印动态规划表
// for(i=0; i<=n; i++) {
// for(j=0; j<=C; j++){
// cout << V[i][j] << "\t";
// }
// cout << endl;
// }
// 回溯寻求解向量
j=C;
int x[10];
for(i=n; i>0; i--) {
if(V[i][j]>V[i-1][j]) {
x[i]=1;
j=j-w[i];
}
else x[i]=0;
}
cout << "(";
for(i=1; i<n; i++) {
cout << x[i] << ",";
}
cout << x[n] << ")\n" << V[n][C] << endl;
return V[n][C];
}
int main()
{
int n,C,i,v[20],w[20];
//cout << "请输入物品个数:";
cin >> n;
//cout << "请输入背包容量:";
cin >> C;
//cout << "请依次输入每个物品的重量:";
for(i=1; i<=n; i++)
cin >> w[i];
//cout << "请依次输入每个物品的价值:";
for(i=1; i<=n; i++)
cin >> v[i];
KnapSack(n,C,w,v);
return 0;
}
运行结果
(0,0,1,1)
65