01背包问题-动态规划

最优解

问题描述

n n n个物品,它们有各自的重量和价值,现有给定承重量的背包,如何让背包里物品价值总和最大?

e g : eg: eg:
背包容量: W = 8 W=8 W=8

i i i(物品编号) w i w_{i} wi(重量) v i v_{i} vi(价值)
123
235
344
457

定义:
v i v_{i} vi——第 i i i个物品的价值;
w i w_{i} wi——第 i i i个物品的重量;
V ( i , j ) V(i,j) V(i,j)——当前背包容量 j j j,前 i i i个物品最佳组合对应的价值。

动态规划递推式

1、边界条件,包容量或者物品数量为0,即 i = 0 o r j = 0 i=0orj=0 i=0orj=0

V ( i , 0 ) = V ( 0 , j ) = 0 V(i,0)=V(0,j)=0 V(i,0)=V(0,j)=0

2、递推条件1,包的容量比商品 i i i小,即` ( j < w i ) (j<w_i) (j<wi) i i i无法装入,此时的价值与前 i − 1 i-1 i1个的价值是一样的;

V ( i , j ) = V ( i − 1 , j ) V(i,j)=V(i-1,j) V(i,j)=V(i1,j)

3、递推条件2,包的容量比商品 i i i小,即 ( j ≥ w i ) (j{\ge}w_i) (jwi) i i i可以放入,此时选择放 i i i还是不放 i i i

  • (1) i i i物品不放入:
    V ( i , j ) = V ( i − 1 , j ) V(i,j)=V(i-1,j) V(i,j)=V(i1,j)
  • (2) i i i物品放入:
    V ( i , j ) = V ( i − 1 , j i ) + v i V(i,j)=V(i-1,j_i)+v_i V(i,j)=V(i1,ji)+vi

V ( i , j ) = m a x { V ( i − 1 , j ) , V ( i − 1 , j − w i ) + v i } V(i,j)=max\{V(i-1,j),V(i-1,j-w_i)+v_i\} V(i,j)=max{V(i1,j),V(i1,jwi)+vi}

填表

1、初始条件, V ( i , 0 ) = V ( 0 , j ) = 0 V(i,0)=V(0,j)=0 V(i,0)=V(0,j)=0

-012345678
0000000000
10
20
30
40

2、按递推条件

-012345678
0000000000
1003333333
2003558888
3003558899
400355881012
  • i = 1 , j = 1 , w 1 = 2 , v 1 = 3 , 有 j < w ( 1 ) , 故 V ( 1 , 1 ) = V ( 0 , 1 ) = 0 ; i=1,j=1,w_1=2,v_1=3,有j<w(1),故V(1,1)=V(0,1)=0; i=1,j=1,w1=2,v1=3,j<w(1),V(1,1)=V(0,1)=0;
  • i = 1 , j = 2 , w 1 = 2 , v 1 = 3 , 有 j = w ( 1 ) , 故 V ( 1 , 2 ) = m a x { V ( 0 , 2 ) , V ( 0 , 2 − w 1 ) + v 1 } = m a x { V ( 0 , 2 ) , V ( 0 , 0 ) + v 1 } = m a x { 0 , 3 } = 3 ; i=1,j=2,w_1=2,v_1=3,有j=w(1),故V(1,2)=max\{V(0,2),V(0,2-w_1)+v_1\}=max\{V(0,2),V(0,0)+v_1\}=max\{0,3\}=3; i=1,j=2,w1=2,v1=3,j=w(1),V(1,2)=max{V(0,2),V(0,2w1)+v1}=max{V(0,2),V(0,0)+v1}=max{0,3}=3;
  • . . . ... ...
  • i = 4 , j = 8 , w 1 = 5 , v 1 = 7 , 有 j > w ( 1 ) , 故 V ( 4 , 8 ) = m a x { V ( 3 , 8 ) , V ( 3 , 8 − w 1 ) + v 1 } = m a x { V ( 3 , 8 ) , V ( 3 , 3 ) + v 1 } = m a x { 9 , 10 } = 10 i=4,j=8,w_1=5,v_1=7,有j>w(1),故V(4,8)=max\{V(3,8),V(3,8-w_1)+v_1\}=max\{V(3,8),V(3,3)+v_1\}=max\{9,10\}=10 i=4,j=8,w1=5,v1=7,j>w(1),V(4,8)=max{V(3,8),V(3,8w1)+v1}=max{V(3,8),V(3,3)+v1}=max{9,10}=10

代码实现

	int **dp = new int*[num];   
	for (int i = 0; i < num ; ++i) {
		dp[i] = new int[W + 1];
	}
	for (int i = 0; i < num; ++i) {
		for (int j = 0; j < W + 1; ++j) {
			dp[i][j] = 0;    //必须先分配初值
		}
	}
	
	for (int i = 1; i < num; ++i) {
		for (int j = 1; j < W + 1; ++j) {
			if (w[i] > j)
				dp[i][j] = dp[i - 1][j];
			else
				dp[i][j] = max( dp[i - 1][j],dp[i - 1][j - w[i]] + v[i] );			
		}
	}

	return dp;
};

最优解回溯

回溯方式

1、 V ( i , j ) = V ( i − 1 , j ) V(i,j)=V(i-1,j) V(i,j)=V(i1,j)时,说明没有选择第 i i i个商品,则返回到 V ( i − 1 , j ) V(i-1,j) V(i1,j)
2、 V ( i , j ) = V ( i − 1 , j − w i ) + v i V(i,j)=V(i-1,j-w_i)+v_i V(i,j)=V(i1,jwi)+vi,说明选择了第 i i i个商品,该商品是最优解组成的一部分,返回到 V ( i − 1 , j − w i ) V(i-1,j-w_i) V(i1,jwi)
3、 i = 0 i=0 i=0时结束。

代码

void findWhat(int** &dp, int w[], int v[], int i, int j) {
	if (i > 0) {
		if (dp[i][j] == dp[i - 1][j]) {
			findWhat(dp, w, v, i - 1, j);
		}
		else if(j>=w[i]&&dp[i][j]==dp[i-1][j-w[i]]+v[i]){
			cout << i << " ";
			findWhat(dp, w, v, i - 1, j - w[i]);
		}

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值