C++使用动态规划解决01背包问题——优化版(附详细代码及图解)

使用动态规划解决01背包问题——优化版

一、引言

在上一篇文章“使用动态规划解决01背包问题(附详细代码及图解)”中介绍了使用动态规划解决01背包问题的思想以及详细代码。
在本篇文章,主要会对代码进行进一步的优化。

二、优化说明

在上一篇文章的代码中:二维数组dp[i][j]存储了 “在前 i 个物品中,不超过容量 j 的情况下可以获得的最大价值” 。这时候我们代码的空间复杂度为n*m。
其实在dp[i][j]这个二维数组中,前i-1维的数组所存储的数值都是十分鸡肋的,这对我们的空间复杂度十分不友好。
因此,在优化代码中,会用一个一维数组dp2[j]来改善这个问题,使得程序的空间复杂度降低。
在这里插入图片描述

三、优化思路

首先,代码的思路和使用二维数组时是一样的,即逐一对每个i与j进行遍历,获得“在前 i 个物品中,不超过容量 j 的情况下可以获得的最大价值” 。
但存储这个最大价值的二维数组变成了一维数组。
核心代码实现的变化如下图所示。

在这里插入图片描述
在优化后的代码中:
最外层的循环每遍历完一次,dp2记录的就是在前 i 个物品中,不超过容量 j 的情况下可以获得的最大价值
最外层的循环在每次遍历前,dp2记录的就是在前 i -1个物品中,不超过容量 j 的情况下可以获得的最大价值。
max(dp2[j],dp2[j-w[i]]+v[i]) 和 **max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])**的作用其实是一样的。dp2[j]在没有进行赋值改变时,他记录的是在前 i -1个物品中,不超过容量 j 的情况下可以获得的最大价值,所以dp2[j]与dp[i-1][j]其实是同一个值。dp2[j-w[i]]+v[i]和dp[i-1][j-w[i]]+v[i]也是同理。

四、重点细节

在优化后的代码中,有一个细节,在里面那层循环中j一开始是为m然后递减的进行遍历。也就是说在遍历m时是从大到下进行遍历的。
如果从小到大遍历,那么就会出现下面这种情况:

在i=2,j=5时,dp2[5]=max(dp2[5],dp2[5-w[2]]+v[2])
dp2[5]就会由1变为5
j继续向后面遍历
在i=2,j=8时,dp2[8]=max(dp2[8],dp2[8-w[2]]+v[2])
dp2[8]就会由5变为9

我们每种物品只有一种,这明显不符合

这是因为在遍历前,dp2[j]记录的还是j-1层的数值,如果从小到大去遍历进行改变那么
前面部分的dp2[j]所记录的值就会变成当前j层的数值
到后面部分的j就会以当前层的数值进行比较,这会导致当前物品可不止放入一件的问题。
而从大到小遍历j的话,就可以完美解决这一问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值