[算法分析] 动态规划 DP 之 1
动态规划 Dynamic Programming
算法题里面最操蛋的, 想得出来就是想得出来, 想不出来拿铜头皮带把你抽的陀螺转你也想不出来的
动态规划
这是第一篇, 所以更像是 DP 从何而来, 要干什么, (去到哪里, 什么人生三问).
拙见, 拙见. 我连工作都没有!! 我是个傻逼!!!
分析
动态规划来自于 DFS, 深度优先搜索. 在 DFS 中, 我们经常遇到一个问题, 就是重复搜索了. 明明这些东西都见过了, 但未来要跑的路, 还要再跑一遍, 这就导致了时间复杂度, 哧儿一下上去了. 所以就有了 记忆化 memorization, 来记忆一种名叫 状态 的东西. 状态是啥, 这不重要, 因为这个因问题而异. 但是有一点很重要, 状态记录了哪些东西见过了 或者 哪些东西他没见过, 这很重要, 因为有了这些信息, 跟据香农的信息熵理论, 我们就不再做无用功了, 因为可能性为 1 的事件, 不产生信息. 回到问题, 利用状态, 我们就能快速判断是否重复, 并在O(1)内给出当前状态下再往后走的解.
那么上述过程, 是一种 top-down 的寻找, 是我们定义好状态后, 去规避去躲开重复的路. 这其实已经是 DP 了, 但是这太被动了, 也不够 elegant (会不能和阿尼亚当同学的).
数学part, 跳过跳过!!
现在带一点数学, Markov Process 马尔可夫过程.
1 |
|
wiki我也看不懂, 只是贴一下. 我的拙见是: 首先这是个概率模型, 变量们互相变来变去是跟据一个概率来的, 这个过程就是 Markov Process. 下面的那个好理解.
A stochastic process is said to be Markov if
$prob(s_{t+1}|s^t)=prob(s_{t+1}|s_{t})$
where $s^{t}$ is the history up to period t and $s_{t}$ is the realization of the state at period t.
那这个玩意儿重要在哪里: 就是在随机过程中,明天的状态只取决于今天的状态. 和之前的状态无关啦。也就是不管你今儿是怎样达到 的,只要你今天的状态是 现在这个数值, 你明天状态的可能性就决定好了.
你看这个马尔可夫过程中确定明天状态的部分, 是不是和 DFS + memo 去躲避重复计算很像? 当然熟悉状态机的朋友, 一下也能看出来, 马尔可夫过程就是个概率分布的状态机.
那跟据马尔可夫过程是不是也能做和 DFS + memo 相同的事了呢? 是的, 但是需要一个概率模型.
在 Markov Process 中, 这个概率模型 也被称之为 转移矩阵 (Transition Mtrix) 而最终结果也被叫做稳态 (stable state). 初始的概率分布, 在经过无数次矩阵乘法过后, 状态会逐渐收敛到稳态.
示例: 如果状态空间只包含了两个状态A和B。如果今天是A,那么明天还是A的概率为0.8。如果今日是B,那么明天还是B的概率为0.7。一开始状态在A, 求稳态方程如下:
1 |
|
这个 pi 结果最后是 0.6 和 0.4. 不管换什么初始都会稳定在这里.
此时问题来了, 面对问题, 我们从哪儿来这个转移矩阵? 答案是 对问题抽象, 寻找子问题. 我们看下上述代码, 无数次的矩阵乘法 就对应了 子问题的重复进行, 而初始状态就是我们问题开始时候的状态, 这个是固定的. 稳定态自然也不是咱们追求的, 咱们要的只是 问题所需的某一状态作为结束.
再简化一下: 在有限状态转移下, 从固定初始状态到固定终结状态的有限状态转移问题.
简而言之
最优子问题, 找 状态转移方程 进行子问题扩大 直到 原问题
思路: 1. 发现递归 -> 2. 从上到下的递归 -> 3. 加入 记忆 的递归 -> 4. 递归 转 迭代 + 记忆-> 5. 优化记忆空间
一般来说, 还是 直接 找 状态转移方程 直接写实在
例题: 打家劫舍1
例题
1. 发现递归: 是 抢 i-1 家 还是 抢 i 和 i-2家 赚
2. 从终末状态开始, 从上到下递归:
1 |
|
3. 加入 记忆 的递归
发现这家抢过了, 以后抢多抢少也确定了(算过了), 直接 return
1 |
|
4. 递归 转 迭代 + 记忆
状态转移从初始开始, 到终末状态结束. Markov Process 开始应用, 我不管你之前的状态了, 我就看后面. 从第一家开始抢, 到每家都看看, 是抢现在这家 + 上上一家 钱多 还是 抢上一家 钱多.
1 |
|
5. 优化记忆空间
熟悉编译里面状态机的朋友看到这个带入状态机就好了, 3状态: 上一家prev2, 上上一家prev1, 现在.
1 |
|