前言
动态规划的思路说起来很简单,但是新遇到一个题目往往就会卡壳,甚至出现解不出来的情况。因此学习的过程中,有必要对面试准备中涉及到的动态规划题目记录,这里只谈思路,不涉及具体实现。
通过分析不仅可以总结思路,更重要的是能从这些问题中找出动态规划题目求解的共性,希望彻底搞定动态规划!。
动态规划
动态规划常用来解决优化问题,与递归分治的思想相似但又不完全相同。动态规划通过找出问题的“最优子结构”,然后组合子问题的解求得最优解,核心思想是通过表格或数组记住已经求过的解(这部分是与递归最大的不同)。
一般求解流程:
- 假设最优子结构
- 在假设的基础上对子问题进行切分
- 定义状态转移方程
- 组合子问题的解(这部分涉及到需要保存解的数据结构构建)
虽然只有4步,但几乎个个都是难点:
- 如何正确的切分问题
- 子问题之间的状态转移方程
- 根据状态转移方程如何进行解的结合
正是这些难点才使得这方面的题目不好解决,在接下来的总结中,重点从这些方面对题目进行思路分析。
题目
《编程之美》1.8 小飞的电梯调度算法
亚洲微软研究院所在的希格玛大厦一共有6部电梯。在高峰时间,每层都有人上下,电梯每层都停。实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法:
由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层。在一楼的时候,每个乘客选择自己的目的层,电梯则计算出应停的楼层。
问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
分析
最优化问题,假设有N个乘客,电梯共有N层,所有乘客爬楼梯层数之和为Ans。
拍脑门算法
从1到N层,求当电梯停在i层时,总结乘客爬楼梯层数之和为Ans[i], 那么最终的答案则是这些结果中的最小值,为min(Ans[1…n])。这种方法时间复杂度为O(n2)O(n^2)O(n2),不可取,不过倒给我们提供了一种思路,“按照电梯层数对问题进行切分”
动态规划分析
假设电梯在第iii层停止,对应乘客爬楼梯层数之和最少为YYY
同时假设第i−1i-1i−1层及以下的乘客数N1N1N1,第i层下的乘客数为N2N2N2,第i+1i+1i+1层及以上下的乘客数为i+1i+1i+1。
那么在这些假设前提下:
- 当电梯在第i-1层停止时,对应乘客爬楼梯层数之和最少为Y−N1+N2+N3Y-N1 +N2 + N3Y−N1+N2+N3,因为低于i层的乘客少爬楼梯,高于i层的乘客需要多爬楼梯,其和相当于人数,同理可得以下:
- 当电梯在第i+1层停止时,对应乘客爬楼梯层数之和最少为Y+N1+N2−N3Y+N1+N2-N3Y+N1+N2−N3
分析到这里,问题的解法就可以出来了,从1到N层电梯,用Ans = 0保存最优解,对每层判断N1+N2N1+N2N1+N2与N3N3N3的大小,当N1+N2<N3N1+N2 < N3N1+N2<N3时,Y+N1+N2−N3>YY+N1+N2-N3 > YY+N1+N2−N3>Y ,说明i+1层才是最优解,继续遍历,否则最优解为YYY, 退出。
复盘
总结解题思路:
- 假设最优子结构:通过假设最优解,得到子问题的表达式。
- 子问题切分:电梯层数
- 状态转移方程:判别式N1+N2<N3N1+N2 < N3N1+N2<N3,仅成立时继续遍历。
- 组合解:一个变量Ans保存即可。