抓不住的动态规划

本文作者分享了自己在学习动态规划过程中遇到的挑战与感悟,包括状态定义的困难、递推公式的理解以及不同类型的动态规划问题。文章通过实例探讨了坐标型、跳跃问题、骰子求和、打劫房屋等经典动态规划问题,总结了解题的关键步骤,并指出动态规划题目虽具挑战性,但也有其乐趣所在。作者决定暂时放下,但计划未来再次深入学习。
摘要由CSDN通过智能技术生成

断断续续磕动态规划已经好几周了,怎么讲,如果非要概括一下这两三周的成果的话,大概就是从入门到放弃……动态规划题虽然没有千千万,但也有典型例题两百题吧,磕了一些网上的教程,磕了geeksforgeeks的dynamic programming,刷了大概40题左右的动态规划题,有些刷了两遍的时候还是得抓耳挠腮,状态怎么定义,状态如何转换。

曾经想过用暴力的方式破解,然后观察其中哪些计算时重复的,然后再对重复计算的东西来进行一个记录。还想到了剪枝之类的,但是往往理想很丰满,现实很骨感,我自己意淫出来的大部分DP的状态定义大部分是错的。很多时候明明得用三维来标记状态,却选了二维,用二维标记选了一维,(但是有时候只需要一维的然后选了二维,结果是对的233333)然后打死都弄不来。而且好多题解用暴力的方式做还真做不来。

持续抗战了前前后后快一个月(虽然中间还有出去玩耍的时候),决定动态规划的抗战到此结束,虽然每次做DP很有自虐或者说是高中学习的快感。怎么讲,首先题目难度在你现有能力往上一点点,不至于难到一步登天,只要花点时间花点心思都能做出来,但是……题目不像BFS或者说DFS那样在一个大致的框架内做不算太大的微小的改变,光是大致的框架就得有好多个,有时候题目啰啰嗦嗦一层套一层,光看懂题目就得费老长一段时间,等定义状态的时候更是云里雾里而且老以为是这样的,其实正确答案又是那样的(This that,comme ci comme ca),然后看完答案之后,长吁一口气,原来是这样的。

虽然很有挑战性,刷起来其实有时候还觉得其乐无穷,但是真的得放弃了,以后会再捡起来,但不是现在,不应该在这上面浪费更多的时间了。

总的来说,动态规划虽然比其他类型的题目灵活,但总体还是有很大一部分的题目都在一定的框架之内,最难的难点是定义各种状态,如果状态定义好,那递推公式也想出来了。(很多时候的思路的过程更多的是先想好递推公式,才能确定定义的状态是对的。)

其实主要的步骤还是

  1. State
  2. Function
  3. Initialize

实现方式有Bottom up,从小到大,还有memorized search,从大问题到小问题。 目前遇到的大部分问题都可以用bottom up的方式解决,(能用bottom up就不用top down了,毕竟bottom up写的多,不容易错)。但是有一类,比如区间型的DP或者search in a 2d matrix, 结果和子结果的相对位置关系不好弄的时候,采用memorized search的方式。

后面是一些简陋的总结吧,主要集中在如何定义状态,以及递推公式这两个步骤。实现上会有一些边界考虑的情况,也挺容易错的,要多举例,或者举反例(我举的反例貌似老是不是反的……)

坐标型动态规划

目前来说,坐标型的动态规划,即左上角走到右下角的这种类型的题目都还算简单,最大,最小,方案个数之类的各种题目。一般都选用bottom up的写法。一般当前答案可能是由上一层/左边得到。典型例题,triangle count,unique path,都是比较简单的坐标型动态规划。总的来说,这类题目大多数还在handle的范围内,除了个别比较变态的题目……

跳跃问题

描述:给出一个非负整数数组,你最初定位在数组的第一个位置。

数组中的每个元素代表你在那个位置可以跳跃的最大长度。

判断你是否能到达数组的最后一个位置。

A =[2,3,1,1,4],返回 true.

A =[3,2,1,0,4],返回 false.

思路:

if(dp[i]==true){
   for(int j=1;j<=A[i]&&size;j++){
     dp[i+j]=true;
   }
}

follow up: 给出最少的跳跃次数

稍微变了一下,但还是很简单,只需要从前往后选一个最小的加1.

dp[i] = min{dp[i-j]}+1 if A[i-j]>=j 

骰子求和

扔 n 个骰子,向上面的数字之和为 S。给定 Given n,请列出所有可能的 S值及其相应的概率。坐标类型,走到最后一步。

思路: 开始定义状态的时候只定义了 f[target],只有一维,自以为是对的,然后……其实是错的。 但增加到二维,分别是分值和第几次之后,思路就很简单了。

f[i][j] += f[i-1][j-k] for k in [1,6]

打劫房屋

在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下 [1,2,3,5]

思路:这题其实很简单,分两种情况,拿第一间房子的时候算一遍,结果为f[n-1],不拿第一间房子的时候算一遍,结果为f[n],然后取最大的一个。

交叉字符串

描述:给出三个字符串:s1、s2、s3,判断s3是否由s1和s2交叉构成。比如 s1 = “aabcc” s2 = “dbbca”

  • 当 s1 = “aadbbcbcac”,返回 true.

  • 当 s3 = “aadbbbaccc”, 返回 false.

思路:看上去像双序列类型的题目,其实是坐标型,因为不能跳过某个字符。一旦不匹配,则为false。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值