c++ 多重背包状态转移方程_01背包问题

本文介绍了动态规划在解决01背包问题中的应用,通过递推公式建立状态转移方程,从朴素的深度优先搜索算法转换为高效的动态规划算法。讨论了如何从递归算法导出动态规划的遍历顺序,并指出动态规划的最优化原理和无后效性。同时,提出了使用滚动数组将空间复杂度从平方级别降低到线性级别的优化技巧。
摘要由CSDN通过智能技术生成

25428699627949eec8c34401ef4f14ca.png

最近在刷Coursera的算法课编程作业,发现两年不碰coding实在是忘得差不多了。做到dp题不得不翻翻书了,发现原来动态规划的基础就没怎么打好,打算写一些dp的题解。本文主要介绍简单的动态规划问题,用于笔者自己整理思路。

从01背包开始:

a25e6aa15561b5b70be949b2a38c5bad.png

用一定的总重量,装最贵的物品。因为每个物品只有装与不装两种策略,故称0/1背包。上题中,单个物品的质量和价值相等(因为是金条,很合理)。

考虑一个朴素的深搜算法,复杂度是O(

)
void 

穷举每个物品放与不放的情况,用当前重量剪枝,最后会形成一棵二叉树。非常地朴素,当然也非常地慢。

反过来考虑的话,用递推,对最后一个物品拿不拿进行分类。可以得到以下的递推式:

3550e1b6c637efb211116f39d0beecf6.png

这方便我们写出一个递归算法:

int 

这个算法是逆推的,和dfs一样也是指数复杂度。

由这个递推方程,或者现在应该叫状态转移方程了,不难看出,“考虑第i个元素和余下wei重量时”的最优解只需知道“考虑第i-1个元素和余下wei重量时”和“考虑第i-1个元素和余下wei-w[i]重量时”的最优解。从动态规划的原理上来讲,这满足最优化原理(最优子结构)和无后效性。从算法实现的角度,它给了我们一个遍历数组的顺序。

75e4a1a3f5b07bc62a0127e7de622951.png

先开一个二维数组dp[i][wei],那么根据状态转移方程,任何一个位置的值都可以由它上方和左上方位置的值确定,并且这个过程是递归的。

cc96ceccafdd4c147c6c55ccabee9ec5.png

那么我们自然确定,以先从左往右,再从上往下的顺序遍历数组。

4e1be5f008538193f73470af8fee545d.png

再预处理一下边界条件

768f7149ae4f257642b01105d06c4ba4.png

就可以愉快地dp啦

for

什么?两层循环?这也太好写了吧。比前面搜索,递归不知道高到哪里去了。最重要的是只要

的时间复杂度!这样本题就能过啦。

但是呢,聪明的小伙伴已经发现啦,本题调用了一个二维数组,用了

的空间复杂度。但是dp过程中事实上只需要用上一行的数据,准确来说是上一行的左半部分。那么自然可以用滚动数组优化一下,把空间复杂度降到线性,这里就不写啦。

总结,动态规划算法本质在于寻找合法的状态转移方程,这一步往往是困难的。带什么参数dp?如何构造良好的遍历顺序?从个人经验来看,从深搜或者递归向动态规划优化可能是一种比较自然的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值