DP&01背包问题&状态压缩

一、DP初步:

1.关于DP:DP实际上就是一个方法论,其实称作“递推公式法”或“状态转移方程法”更加贴切。最好把它理解成一个“公式法”的东西,总之就是通过一些数据之间的关系,来搞出一个状态转移方程,再把这个方程体现到代码上即可。不会像其他的很多算法一样,会存在代码实现上的困难——DP的实现的难点集中于状态转移方程的推导。

DP就像是心中有了一套运算的法则,然后用代码来实现这样一套算法
(当你开始写DP的时候,你的心里应当已经有答案了)
弗洛伊德---也是DP的一个实例(是通过公式来得出结果的!)
最长问题--一般就不包含最优子结构性质了(往往会耍出相互独立的效果)

2.DP的应用领域多半是“最优”类的问题,譬如“最长公共子序列”等,总之看到“最大”“最优”等字眼时,往往昭示着这个题目会与DP相关。

3.DP与分治的区别:

分治--分出来的东西都是相互独立没什么联系的,而DP往往需要不断地通过上一级的结果得到这一级的结果,也就是需要子问题的状态来推导出当前问题的状态。
由此只要发现了子问题中有不独立的--直接冲DP开始找规律即可。因为子问题如果独立的话就没得规律找了,不可能会用DP来做

4.DP一些潜在的问题:
也正是因为不独立,在做反复的子问题计算的时候,可能会有很多数据的重复计算!如斐波那契。

5.潜在问题的两种解决方案:
①.Lookup(备忘录)法--仍然和递归的形式很相像,是自顶向下来求解的。只是建立了备忘录减少了递归调用的次数。实际上就是剪枝法--它把会用到的数据全存起来,但是有时候,在有时间限制的竞赛里,往往不行。

由此:如果用递归会超时,(即使没有超时,做优化的时候也要重点去想一想有没有重叠子问题!不过像二叉树这种的,是典型的没有重叠的)这时候就应该看看会不会有重叠子问题,即子问题的重复计算
如果有,那么就该用DP

但是不存在子问题的重复计算的话--用递归&分治往往会更好

②Dptable法:更难想一点,虽然会更优。它的实现是自底向上,真正通过先求解子问题再向上逐级推导出问题的答案。

6.后续DP的学习思路:
①DP的特征非常明显,注意往死里刷--总结规律(哪些数据需要找规律)--靠直觉!但是一般难度的题,该用哪组数据,是很明显的。不过DP的题仍然是应该刷的最多的。

※②递归树总能给你一些不一样的思路,本文后面会提到。

对于上述DP初步整理的总结:


 

最优子结构性质:需要求解的问题也包含了子问题的最优解,比如最短路径问题。但是很显然,最长路径是没有最优子结构性质的。

也就是说,求解的时候先求解子问题,用一维&二维数组(一般的题也就到二维就够了)来保存子问题的答案,然后推得目标解。

自底向上的推导,一般称之为迭代--逐步推演。

这个存入的特殊的值很重要!一定要看清题目的值域,有时候错就会错在一些边界条件没有卡好---比如有测试用例是int型的最小值,而特殊值就设置的是int型的最小值,这不可。或者是会想当然的觉得各个子问题的解的值都应当是正数而把特殊值初始化为-1。

但是有一种情况,也就是当解的值会代表数组的下标的时候,这种情况下特殊值给-1是完全ok的

当只需要对应的结果的时候不用开对应的数组,直接一个个变量的叠加上去就行了。比如计算第n项斐波那契数组的值的时候,不断地更新累加的两个数的值即可 

备忘录处理起来相对要简单得多---只需要在递归的过程中加一步是否当前解存在于lookup中的判断即可

不要忘记根据题目的状态来作是否是DP问题的判断!!

 上图就是一种很典型的递推方式--因为DP[6]和DP[4]还有DP[2]都存储了6、4、2状态下的解的种类数,而他们都可以通过一步就得到DP[7]

但是还有很重要的一点--确定转移方程的时候,只要枚举不是过于麻烦,还是多枚举一些比较好--比如这个题,前六项和斐波那契的值一模一样,但是到了第七项,就和斐波那契不再一样了。其实通过公式也能看出来--斐波那契是前两项和,而这个题目的公式实际上是前三项的和,怎么可能会是相等的呢

由此DP可能是算法题中最需要动笔的几种题型之一,要想做数学题一样去捋规律,枚举可能性。

上面这张图,总结了表&备忘录的选择--当部分子问题不需要进行计算的时候,备忘录往往会更好。因为DPtable总是需要去填充进去所有解的。

注意面试题里的算法题一定会是立足于应用场景中的!!要试着从应用场景抽离出模型来----最常见的也许就是图模型和贪心模型了!

对于上述DP初步整理的一些补充:

1.斐波那契那种的递归,可以通过加一个总和的参数来作尾递归的优化-----实质上就是,原本要靠保存整个的递归状态来保存当前的和的状态,现在给改成了靠维护一个存储总和的变量来保存当前的和的状态。

2.再升华一下--DP中实际上会有很多共通的子问题,子问题有可能会重复出现,更具体地说,解是可以重复用到的。

3.DP中有些代码会是从数组下标为1开始来计算第一个子问题的解,有时候是通过下标为0,只要看最后返回的东西是否对应的上它选择的下标的计算的模式即可。

 上面展示了剪枝的一种书写模式---总之思路就是,如果备忘录里有,直接返回。如果备忘录里没有,那就先记录到备忘录里,再返回出去这个值

4.要注意构建DPtable和lookup永远是优先级最低的!要先捋完整此题目的思路,确定了转移方程,也就是推导关系得出之后,再去添加备忘录等

最后,机哥の总结:

 

 

二、01背包问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值