目录
一、单方向移动(青蛙跳台阶、爬楼梯)问题
1、问题
2、确定动态规则(DP、状态方程)
3、确定初始值
4、动态规划算法代码实现
(1)完整代码
(2)程序速度优化
二、可选路径问题(多方向移动、机器人移动)问题
1、问题
2、确定动态规则(DP、状态方程)
3、确定初始值
4、动态规划算法代码实现
(1)完整代码
(2)程序速度优化
5、数学组合求解机器人移动问题
三、移动中最值(最小路径和)问题
1、问题
2、确定动态规则(DP、状态方程)
3、确定初始值
4、动态规划算法代码实现
(1)完整代码
(2)程序速度优化
动态规划算法实现------空间中的移动(路径)问题
在前面一章中,我们从整体上概括了动态规划算法的求解步骤,下面我们用动态规划算法来解决常见的移动(路径)问题,从求解过程中,我们可以进一步理解动态规划算法是如何实现的。
一、单方向移动(青蛙跳台阶、爬楼梯)问题
1、问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?
2、确定动态规则(DP、状态方程)
本题是一个单方向移动问题。由于青蛙每次可以跳1级台阶或2级台阶,青蛙可以由第n-1级或第n-2级跳到第n级,因此,青蛙跳到n级的累计跳法是青蛙跳到第n-1级的累计跳法与青蛙跳到第n-2级的累计跳法之和,也即青蛙处于第n个状态的累计跳法是第n-1个状态的累计跳法和第n-2个状态的累计跳法的和。记累计跳法为dp[i],可以看作是第i个状态,则动态规则DP:dp[i]= dp[i-1]+ dp[i-2]。在本例中,青蛙每次跳一个台阶或二个台阶是实现状态的方式,这两种方式决定了当前状态dp[i]是由直接相关的两个状态dp[i-1]、dp[i-2]参与计算。
3、确定初始值
再来确定初始值,考虑到计算机的循环的索引(下标)从0开始,dp[1]= dp [0]+ dp[-1]中出现-1状态,显然-1不适合为循环的索引,因而第1级需要单独处理。另外,青蛙跳到第2级,即进入第2个状态,有2种跳法,为统一符合动态规则DP:dp[2]= dp [1]+ dp [0],我们需要规定dp [0]=1,显然不偏离计算结果,完全是统一方便计算。第1级即为初始状态,显然累计跳法为1,可以记为dp[1]=1。
4、动态规划算法代码实现
(1)完整代码
下面代码是按上述分析过程实现的,完全体现了我们上面对动态规划的论述,从代码中就能看到动态规划算法的思想,我们可以结合下面代码来理解动态规划算法在本问题中的应用。
def frog_jump(n):#当只跳一级时,也即只有一个状态,没有状态转移,特别情况,单独进行处理。if n <= 1: return 1else:# 生成一个n+1长度的列表为了存放青蛙跳到各台阶的跳法,索引1表示青蛙跳到第1个台阶,依次类推。# 由于增加了0索引,因此列表长度不是n,而是n+1。# 0不造成计算结果的影响,下面等效于dp=[None for i in range(0,n+1)]dp = [0 for i in range(0, n + 1)]#确定普通情况初始值。dp[0] = 1dp[1] = 1#计算普通情况。for i in range(2, n + 1):dp[i] = dp[i - 1] + dp[i - 2]#动态规则(DP)return dp[n]print(frog_jump(10))
运行结果:
(2)程序速度优化
上面代码非常适合我们理解动态规划算法,但在实际应用中,我们也希望提高计算速度,因而,我们没必要把青蛙每跳一个台阶的累计跳法保存下来,我们在循环中仅仅需要保留最近两个状态的值即可得到当前状态的值。上面代码可以简化为下面代码,下面代码更节省内存资源。
def frog_jump(n):#当只跳一级时,也即只有一个状态,没有状态转移,特别情况,单独进行处理。if n <= 1: return 1else:#普通情况初始值。x = 1y = 1#计算普通情况。for i in range(2, n + 1):x, y = y, y + x #动态规则(DP)#上行代码等效于下面。#y=y+x#x=yreturn yprint(frog_jump(10))
运行结果: