动态规划解决台阶问题求解

问题描述:

给定n级台阶,每次走1,2,3步,求解所有可走步骤

8个台阶,上台阶的人一次最多上3个台阶,问上这个8个台阶有多少种方法?

解题思路:

采用动态规划的思想,将大问题划分为若干个子问题,然后递归的解决每个可能的子问题。

首先,先考虑corner case:

1. 当只有一个台阶,那么有1种走法;

2. 当前只有两个台阶,那么有2种走法;

3. 当前有三级台阶,那么就存在4种走法;

接下来就要考虑如何划分子问题,在划分子问题的时候,存在三种情况,分别为:

1. 当前状态走一个台阶, 需要计算子问题 DP(n-1)

2. 当前状态走两个台阶, 需要计算子问题 DP(n-2)

3. 当前状态走三个台阶, 需要计算子问题 DP(n-3)

把三个子问题的解加起来就是当前问题的解。

台阶求解问题的状态转移公式为:

f(n)=f(n?1)+f(n?2)+f(n?3)

cornercase:f(1)=1,f(2)=2,f(3)=4

然后,写点代码吧。(人生苦短,选择python吧)

最简单的解决方式

首先采用最简单,最直接的动态规划思想进行解决:

def solution3(n):
    ‘‘‘
    采用动态规划,递归调用
    存在大量的重复子问题的计算
    f(n) = f(n-1) + f(n-2) + f(n-3)
    ‘‘‘

    # corner case
    if n == 1: return 1
    if n == 2: return 2
    if n == 3: return 4

    return solution3(n - 1) + solution3(n - 2) + solution3(n - 3)

这种最简单的动态规划,采用递归调用的方式计算子问题,但是会存在大量的重复子问题的计算。我们需要采用一些策略解决重复子问题的计算。

记录已经解决的子问题

为了解决重复子问题的计算,可以采用额外的存储空间记录已经解决了的子问题。

sub_problem = {}
def solution2(n):
    ‘‘‘
    采用动态规划,但是记录已经解决了的自问题,不重复计算。
    需要额外的存储空间。
    ‘‘‘

    if n == 1: return 1
    if n == 2: return 2
    if n == 3: return 4

    sub1 = None
    if n - 1 in sub_problem:
        sub1 = sub_problem[n-1]
    else:
        sub1 = solution2(n - 1)

    sub2 = None
    if n - 2 in sub_problem:
        sub2 = sub_problem[n-2]
    else:
        sub2 = solution2(n - 2)

    sub3 = None
    if n - 3 in sub_problem:
        sub3 = sub_problem[n-3]
    else:
        sub3 = solution2(n-3)

    return sub1 + sub2 + sub3

采用Back Trace由小到大的解决问题

在动态规划中,经常采用Back Trace的方法由小问题逐步计算大的问题,这样可以不再采用递归调用,不重复计算子问题。

这是一种最优的求解方式。

def solution(n):
    ‘‘‘
    采用动态规划,并且采用back trace从小问题向大问题回溯
    没有重复计算的子问题
    ‘‘‘

    so = {}
    so[1] = 1
    so[2] = 2
    so[3] = 4

    for idx in range(4, n+1):
        so[idx] = so[idx-1] + so[idx-2] + so[idx-3]

    return so[n]

获取所有可能的台阶走法

上面的三种方式只能计算最终的求解,也就是说只能计算给定n个台阶的情况下最终有多少种走法,但是不能给出每一种走法的过程。

如果要枚举所有的可能走法,这个时候就需要采用深度优先遍历的方式,每次选择一种走法,如果当前已经到达第n级台阶,则把当前的走法加入到枚举结果中,然后回溯到上一个状态,枚举其他的走法。

代码示例:

def get_all_combination(n):
    ‘‘‘
    采用DFS获得所有可能的台阶的走法
    上面提到的动态规划只能给出最终有多少中解,但是不能记录每一种走法, 如果想要记录每一种走法,可以采用DFS进行走法遍历。
    ‘‘‘

    all_so = []
    so = []

    combination(n, so, all_so)

    return all_so

def combination(n, so, all_so, total=0):
    ‘‘‘
    采用DFS获得所有可能的台阶的走法
    上面提到的动态规划只能给出最终有多少中解,但是不能记录每一种走法, 如果想要记录每一种走法,可以采用DFS进行走法遍历。
    ‘‘‘

    if total == n:
        copy = []
        for item in so:
            copy.append(item)
        all_so.append(copy)
        return

    if total > n:
        return

    for stair in range(1, 4):
        so.append(stair)
        combination(n, so, all_so, total+stair)
        so.pop()

上面的代码调用:

if __name__ == ‘__main__‘:
    print solution3(8)
    print solution3(4)

    print ‘----------------------------------------------‘
    print solution2(8)
    print solution2(4)

    print ‘----------------------------------------------‘
    print solution(8)
    print solution(4)

    print ‘----------------------------------------------‘
    print ‘all possible ways:‘
    so = get_all_combination(8)
    print len(so)
    for s in so:
        print s

获取所有的可能的走法的输出:

----------------------------------------------
all possible ways:
81
[1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 2]
[1, 1, 1, 1, 1, 2, 1]
[1, 1, 1, 1, 1, 3]
[1, 1, 1, 1, 2, 1, 1]
[1, 1, 1, 1, 2, 2]
[1, 1, 1, 1, 3, 1]
[1, 1, 1, 2, 1, 1, 1]
[1, 1, 1, 2, 1, 2]
[1, 1, 1, 2, 2, 1]
[1, 1, 1, 2, 3]
[1, 1, 1, 3, 1, 1]
[1, 1, 1, 3, 2]
[1, 1, 2, 1, 1, 1, 1]
[1, 1, 2, 1, 1, 2]
[1, 1, 2, 1, 2, 1]
[1, 1, 2, 1, 3]
[1, 1, 2, 2, 1, 1]
[1, 1, 2, 2, 2]
[1, 1, 2, 3, 1]
[1, 1, 3, 1, 1, 1]
[1, 1, 3, 1, 2]
[1, 1, 3, 2, 1]
[1, 1, 3, 3]
[1, 2, 1, 1, 1, 1, 1]
[1, 2, 1, 1, 1, 2]
[1, 2, 1, 1, 2, 1]
[1, 2, 1, 1, 3]
[1, 2, 1, 2, 1, 1]
[1, 2, 1, 2, 2]
[1, 2, 1, 3, 1]
[1, 2, 2, 1, 1, 1]
[1, 2, 2, 1, 2]
[1, 2, 2, 2, 1]
[1, 2, 2, 3]
[1, 2, 3, 1, 1]
[1, 2, 3, 2]
[1, 3, 1, 1, 1, 1]
[1, 3, 1, 1, 2]
[1, 3, 1, 2, 1]
[1, 3, 1, 3]
[1, 3, 2, 1, 1]
[1, 3, 2, 2]
[1, 3, 3, 1]
[2, 1, 1, 1, 1, 1, 1]
[2, 1, 1, 1, 1, 2]
[2, 1, 1, 1, 2, 1]
[2, 1, 1, 1, 3]
[2, 1, 1, 2, 1, 1]
[2, 1, 1, 2, 2]
[2, 1, 1, 3, 1]
[2, 1, 2, 1, 1, 1]
[2, 1, 2, 1, 2]
[2, 1, 2, 2, 1]
[2, 1, 2, 3]
[2, 1, 3, 1, 1]
[2, 1, 3, 2]
[2, 2, 1, 1, 1, 1]
[2, 2, 1, 1, 2]
[2, 2, 1, 2, 1]
[2, 2, 1, 3]
[2, 2, 2, 1, 1]
[2, 2, 2, 2]
[2, 2, 3, 1]
[2, 3, 1, 1, 1]
[2, 3, 1, 2]
[2, 3, 2, 1]
[2, 3, 3]
[3, 1, 1, 1, 1, 1]
[3, 1, 1, 1, 2]
[3, 1, 1, 2, 1]
[3, 1, 1, 3]
[3, 1, 2, 1, 1]
[3, 1, 2, 2]
[3, 1, 3, 1]
[3, 2, 1, 1, 1]
[3, 2, 1, 2]
[3, 2, 2, 1]
[3, 2, 3]
[3, 3, 1, 1]
[3, 3, 2]

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-29 22:53:37

动态规划解决台阶问题求解的相关文章

动态规划解决最长公共子序列问题(转)

原文链接 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 解决思想: 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后

动态规划解决0-1背包问题

这几天算法老师布置了一个作业是关于背包问题的,在这里记录一下解决的过程: 一:背包问题的描述 有n1,n2,n3....个物品,每个物品的重量为w1,w2,w3.....,每个物品的价值为v1,v2,v3....,现在有一个承重量为C的背包,求出要怎样放物品才能使的装入背包的物品价值总和最大.由于每个物品只有一个,并且只能选择放或不放,因此用0表示物体没有放进背包中,1表示物体放进背包中 二:分析过程(以具体的例题来分析) 题目描述: 现有一个可以承重为6的背包bag,以及3个物品,它们的重量分

python动态演示动态规划解决矩阵连乘

矩阵连乘:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1.确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少.输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数. 若A是一个p*q的矩阵,B是一个q*r的矩阵,则其乘积C=AB是一个p*r的矩阵.数乘次数是p*q*r. 动态规划算法与分治法类似,其基本思想也就是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,简

动态规划解决“最大子数组”问题

TODO: 动态规划到底是个什么玩艺? ref:http://www.cnblogs.com/waytofall/archive/2012/04/10/2439820.html I 只考虑怎样产生更大的子组和: 假设处理到第i个节点时: 1. 考虑是否i节点是否可使子组的和变大 a) 如果i节点大于0,则最大子组和是前面求到的数组和 加上 i节点值 b) 如果i节点小于0(等于0的话,值可以带上i,也可以不带上i,无所谓),当最大子数组的和是前面求的子组和 2. 然后考虑最大值是否应该更新了 a

用js实现动态规划解决背包问题

动态规划的原理: 移至到该同学的博文中,讲解的声动易懂 https://www.jianshu.com/p/a66d5ce49df5 现在主要是用js来实现动态规划 function bb(v, w, total) { var maxValue = [];//用来存储所有的最优值的二维数组 //i行表示物品种类,j列表示容量,v是价值,w是容量,total是总容量限制 //表中的每一个值,都是最优值 //每次都从小容量开始计算,逐步增加到大容量 for (var i = 0; i < w.len

动态规划解决机器人网格路径问题!

想获得更好的排版,请移步个人博客: https://pushy.site 无障碍物 题目(原题见 LeetCode - 62. 不同路径):一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ).机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为"Finish").问总共有多少条不同的路径? 示例 1: 输入: m = 3, n = 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角.

c++动态规划解决数塔问题

#include <iostream>#include <algorithm> using namespace std; /************************************************************************//* 数塔问题 *//************************************************************************/const int N = 50;//为了算法写

动态规划解决杭电OJ1080题——LCS的变种

首先上题目: Human Gene Functions Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2570    Accepted Submission(s): 1451 Problem Description It is well known that a human gene can be considered as a se

动态规划解决hdu龟兔赛跑

import java.util.Scanner; class test { private double dp[];//用来存储每段的最短时间 private double p[];//用来存储每个充电站点离起点的距离 private int n,c,t; private double vr,vt1,vt2; private double Length; public boolean Solution(){ System.out.print("请输入每个站点离起点的距离:"); Sc