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

0-1背包问题是用一个有限容量的背包,尽可能地装下更多价值的东西,每个物品的数量都是1,以下面的数据为一个例子:

价值重量
物品1151
物品2202
物品3304
物品4405

如今你有一个容量为7的背包,请问如何装才能使你的装下的物品总价值最高?

这里我就不论证为什么这类问题要用动态规化来解决了,着重分析该问题如何使用动态规划来解决。

使用一个二维dp[ i ][ j ]数组来记录数据

背包容量01234567
物品1
物品2
物品3
物品4

我们以下标的形式分别标注行、列为第0行,第1行…… 第0列,第1列……

dp[ i ][ j ]内的 i 表示只装下标为[0,i]的物品,例如:i=2,表示只装下标为[0,2]的物品,就是只考虑物品1,物品2,物品3

 dp[ i ][ j ]内的 j 表示背包容量,例如j=3,表示背包当前容量为3

dp[ i ][ j ]内每一个小单元格,记录只考虑下标为[0, i]的物品,在当前背包容量为j时能装下物品的最大价值,例如:dp[ 2 ][ 3 ]记录只考虑物品1,物品2,物品3时,在背包容量为3时,背包内装下物品的最大价值

解释完dp数组的基本功能后,接下来就是dp数组的初始化,

dp数组的初始化

显而易见的,当背包容量j=0时,背包内装下物品的最大价值都为0,

当背包容量j>0时,只装物品1,背包内装下物品的最大价值都为15,

因此我们就可以初始化我们的表格为:

背包容量01234567
物品1015151515151515
物品20
物品30
物品40

初始化完成后,就是根据递推关系填写表格

根据递推关系填写表格

dp[ i ][ j ]有两个递推方向

第一个,当 j  < weight[ i ]时,即背包容量比物品i的容量还小,即使我们把背包里的东西都拿出来了,还是放不进背包里,现在考虑不考虑物品i结果都是一样的,背包内装下物品的最大价值就可以直接等于不考虑物品i时的最大价值

那么此时dp[ i ][ j ] = dp[ i - 1][ j ]

第二个,当j  > weight[ i ]时,这时就可以放得下物品i了

但此时有会出现两种情况了,因为背包容量+1,+1,这样慢慢加起来的,如果只有+1,你不能直接把物品i装进背包里

这时你有两个选择了

选择1:背包容量就加了一点点,不能直接放进物品i,那还不如不管它 dp[ i ][ j ] = dp[ i - 1][ j ]

选择2:你把原来背包中的物品拿出来一部分,空出的位置装下物品i,这样 dp[ i ][ j ] = dp[ i-1 ][ j - weight( i )]  + value( i ),就是将背包空出足够空间装物品i的情况,空出后的最大价值 + 物品 i 的价值 = 当前j容量下背包的最大价值

比较上面两种选择的最大价值,选择最大的价值就可以

以下是代码实例:

void test02()
{
	vector<int> value = { 15,20,30,40 };   //记录物品的价值
	vector<int> weight = { 1,2,4,5 };   //记录物品的重量
	int bagWeight = 7;   //背包容量
	vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0));

	//初始化dp数组
	//当背包容量j=0时,背包内装下物品的最大价值都为0,
	for (int i = 0; i < weight.size(); i++)
	{
		dp[i][0] = 0;
	}
	//当背包容量j>0时,只装物品1,背包内装下物品的最大价值都为物品1的价值
	for (int i = 1; i <= bagWeight; i++)
	{
		dp[0][i] = value[0];
	}

	//遍历dp数组,填写表格
	for (int i= 1; i < weight.size(); i++) {  //遍历物品
		for (int j = 1; j <= bagWeight; j++) {  //遍历背包容量
			/*
			第一个,当 j  < weight[ i ]时,即背包容量比物品i的容量还小
			即使我们把背包里的东西都拿出来了,还是放不进背包里
			现在考虑不考虑物品i结果都是一样的
			背包内装下物品的最大价值就可以直接等于不考虑物品i时的最大价值
			*/
			if (j < weight[i])
			{
				dp[i][j] = dp[i - 1][j];
			}

			//第二个,当j  > weight[ i ]时,这时就可以放得下物品i了
			else
			{
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
			}

		}
	}

	cout << dp[weight.size() - 1][bagWeight] << endl;
}

 输出结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值