【动态规划之0-1背包问题】

【问题描述】

0-1背包问题:给定 n 种物品和一背包。物品 i 的重量是wi其价值为vi,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?

在选择装入背包的物品时,对每种物品 i 只有两种选择,即装人背包或不装入背包。不能将物品 i 装入背包多次,也不能只装入部分的物品 i 。因此,该问题称为0-1背包问题。

此问题的形式化描述是,给定c>0,wi>0,vi>0,1 ≤ i ≤ n,要求找出一个n元0-1向量(x1,x2,···,xn),xi ∈{0,1},1≤i<h,使得 ∑ i = 1 n w   i   ∗ x   i   ≤ c \sum_{i=1}^n{w~i~*x~i~}≤c i=1nw i x i c,而且 ∑ i = 1 n v   i   ∗ x   i   \sum_{i=1}^n{v~i~*x~i~} i=1nv i x i 达到最大。因此,0-1背包问题是一个特殊的整数规划问题:
m a x ∑ i = 1 n v   i   ∗ x   i   max\sum_{i=1}^n{v~i~*x~i~} maxi=1nv i x i 
∑ i = 1 n w   i   ∗ x   i   ≤ c \sum_{i=1}^n{w~i~*x~i~}≤c i=1nw i x i c
x   i   ∈ ( 0 , 1 ) , 1 ≤ i ≤ n x~i~\in(0,1),1≤ i ≤ n x i (0,1),1in

【算法分析】

1.最优子结构性质

0-1背包问题具有最优子结构性质。设(y1,y2,···,yn)是所给0-1背包问题的一个最优解,则(y2,y3,–·,yn)是下面相应子问题的一个最优解:
m a x ∑ i = 2 n v   i   ∗ x   i   max\sum_{i=2}^n{v~i~*x~i~} maxi=2nv i x i 
∑ i = 2 n w   i   ∗ x   i   ≤ c − w   i   ∗ y   1   \sum_{i=2}^n{w~i~*x~i~}≤c-w~i~*y~1~ i=2nw i x i cw i y 1 
x   i   ∈ ( 0 , 1 ) , 2 ≤ i ≤ n x~i~\in(0,1),2≤ i ≤ n x i (0,1),2in
因若不然,设(z2,z3,···,zn)是上述子问题的一个最优解,而(y2,y3,··,yn)不是它的最优解。由此可知, ∑ i = 2 n v   i   ∗ z   i   > ∑ i = 2 n v   i   ∗ y   i   \sum_{i=2}^n{v~i~*z~i~}>\sum_{i=2}^n{v~i~*y~i~} i=2nv i z i >i=2nv i y i ,且
w   1   ∗ y   1   + ∑ i = 2 n w   i   ∗ z   i   ≤ c w~1~*y~1~+\sum_{i=2}^n{w~i~*z~i~}≤c w 1 y 1 +i=2nw i z i c。因此,
v   1   ∗ y   1   + ∑ i = 2 n v   i   ∗ z   i   > ∑ i = 1 n v   i   ∗ y   i   v~1~*y~1~+\sum_{i=2}^n{v~i~*z~i~}>\sum_{i=1}^n{v~i~*y~i~} v 1 y 1 +i=2nv i z i >i=1nv i y i 
w   1   ∗ y   1   + ∑ i = 2 n w   i   ∗ z   i   ≤ c w~1~*y~1~+\sum_{i=2}^n{w~i~*z~i~}≤c w 1 y 1 +i=2nw i z i c
这说明(y1,z2,···,zn)是所给0-1背包问题的一个更优解,从而(y1,y2,···,yn)不是所给0-1背包问题的最优解。此为矛盾。

2.递归关系

设所给0-1背包问题的子问题
m a x ∑ k = i n v   k   ∗ x   k   max\sum_{k=i}^n{v~k~ * x~k~} maxk=inv k x k 
m a x ∑ k = i n w   k   ∗ x   k   ≤ j max\sum_{k=i}^n{w~k~ * x~k~}≤j maxk=inw k x k j
x   k   ∈ ( 0 , 1 ) , i ≤ k ≤ n x~k~\in(0,1),i≤ k ≤ n x k (0,1),ikn
的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,···,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下:
m ( i , j ) = { m a x { m ( i + 1 , j ) , m ( i + 1 , j − w   i   ) + v   i   } j ≥ w   i   m ( i + 1 , j ) 0 ≤ j ≤ w   i   m(i,j)=\left\{ \begin{array}{rcl} max\lbrace m(i+1,j),m(i+1,j-w~i~)+v~i~\rbrace & & { j≥w~i~}\\ m(i+1,j) & & {0≤j≤w~i~} \end{array} \right. m(ij)={max{m(i+1j),m(i+1jw i )+v i }m(i+1j)jw i 0jw i 
m ( n , j ) = { v   n   j ≥ w   n   0 0 ≤ j ≤ w   n   m(n,j)=\left\{ \begin{array}{rcl} v~n~ & & { j≥w~n~}\\ 0 & & {0≤j≤w~n~} \end{array} \right. m(nj)={v n 0jw n 0jw n 

3.算法描述

基于以上讨论,当wi(1≤i≤n)为正整数时,用二维数组m[ ][ ]来存储m(i,j)的相应值,可设计解0-1背包问题的动态规划算法Knapsack(具体实现见【C++代码实现】)。
按上述算法Knapsack计算后,m[1 ][c ]给出所要求的0-1背包问题的最优值。相应的最优解可由算法Traceback计算如下。如果m[1 ][ c]=m[ 2][c ],则x1=0,否则x1=1,当x1=0时,由mm[ 2][c ]继续构造最优解。当x1=1时,由m[ 2][c -w1]继续构造最优解。依次类推,可构造出相应的最优解(x1,x2,···,xn)。

【C++代码实现】

//解0-1背包问题的动态规划算法
template<class Type>
void Knapsack(Type v, int w, int c, int n, Type** m)
{
	int jMax = min(w[n] - 1, c);
	for (int j = 0; j <= jMax; j++)m[n][j] = 0;
	for (int j = w[n]; j <= c; j++)m[n][j] = v[n];
	for (int i = n - 1; i > 1; i--) {
		jMax = min(w[i] - 1, c);
		for (int j = 0; j <= jMax; j++)m[i][j] = m[i + 1][j];
		for (int j = w[i]; j <= c; j++)m[i][j] = max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);
	}
		m[1][c] = m[2][c];
		if (c >= w[1])m[1][c] = max(m[1][c], m[2][c - w[1]] + v[1]);
}
//构造最优解
template<class Type>
void Traceback(Type** m, int w, int c, int n, int x)
{
	for (int i = 1; i < n; i++)
		if (m[i][c] == m[i + 1][c])x[i] = 0;
		else { x[i] = 1; c -= w[i]; }
	x[n] = (m[n][c]) ? 1 : 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值