动态规划——01背包问题滚动数组(一维数组)

看了好几天的背包问题。。。终于有了一点浅显的理解
一开始学完01背包的二维写法,再看一维写法是一脸懵逼的,自己推导了几遍过程,终于是理解了!!!分享一下蒟蒻的心得

问题如下:有n个重量和价值分别为wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
输入:n=4 (w,v)={(2,3),(1,2),(3,4),(2,2)}
输出:7
最大负重为5

如果学过01背包的二维数组写法,那么应该会发现若是递推顺序是正序,那么我们需要用到的是左上方和正上方的数据,如下图在这里插入图片描述
当计算dp[i+1][]时,dp[i-1][]的部分就用不到了。
那么用一维数组又是怎么做的?我们是把上面讲过的左上方和正上方的部分结合起来,从后往前推导
从第一个物品开始,在前面更新的数组基础上继续去更新DP数组的内容,直到没有物品为止。

核心代码如下:

for (int i = 0; i < 4; i++) {
		for (int j = bag_w; j >=w[i]; j--) 
				dp[j] = max(dp[j], dp[j - w[i]] + v[i]);

bag_w为重量上限

推导过程如下:
dp[]右边是一维数组下标
在这里插入图片描述
举个例子,在枚举完i=0的情况时,i=1时使用的是上一次更新完的数组,
dp[j]=max(dp[j],dp[j-w[1]]);等号右边的dp[j]是上一次更新的,即使一维数组里面的dp[j],dp[j-w[1]]相当于二维数组的dp[i-1][j],dp[i-1][j-w[1]],这样,我们就把二维数组进行了降维。

比如说数塔问题,就是一行一行地去更新,也就是在一维数组里面不断滚动

可以试着去推导,如果是正序的话,同一个物品可能会多次使用,
例如,i=0时,dp[2]=3,dp[3]=3,dp[4]=6,注意了,这里dp[4]=max(dp[4],dp[4-w[0]+v[0])=6;可以看到,在dp[2]的基础上,又放入了物品1,这就变成了完全背包而不是01背包了。

切记,一维必须是逆序的,而二维可以正序也可以逆序。

### 使用动态规划一维数组解决0-1背包问题 对于0-1背包问题,当应用一维滚动数组方法时,核心思路在于通过优化空间复杂度来减少内存占用。具体而言,在构建解决方案的过程中仅需维护一个长度为容量加一的一维数组`dp[]`,其中每一个元素代表对应容量下的最优解(即最大价值)。此过程中的遍历顺序至关重要:应先按正序遍历物品列表,随后针对每件物品以逆序方式更新剩余可用容量范围内的状态值。 #### 动态转移方程 设`weight[]`表示各物品的质量,`value[]`表示对应的收益,则有如下递推关系: \[ dp[j]=\max(dp[j],dp[j-w_i]+v_i)\] 这里\(w_i\)指代第i项商品质量而\(v_i\)为其带来的效益;上述表达式的含义是在给定条件下决定是否选取该物件使总分达到最高水平[^3]。 #### Python代码实现 下面给出一段Python程序用于演示这一算法的具体操作流程: ```python def knapsack_01(weights, values, capacity): n = len(weights) # 初始化dp数组,默认情况下所有位置都填充为0 dp = [0] * (capacity + 1) for i in range(n): # 遍历每个物品 for j in range(capacity, weights[i]-1, -1): # 对于每个可能的重量,倒序处理 dp[j] = max(dp[j], dp[j - weights[i]] + values[i]) return dp[-1] if __name__ == "__main__": weight = [5, 4, 6, 3] value = [10, 40, 30, 50] W = 10 result = knapsack_01(weight, value, W) print(f"The maximum total value is {result}") ``` 这段脚本定义了一个名为`knapsack_01()`的功能函数接收三个参数——物品质量和价格列表以及背包容积上限作为输入,并返回所能获得的最大累积分数。内部逻辑遵循前述描述的过程逐步完成计算任务并最终输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值