码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-06 11:10:13      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:动态规划   台阶求解   回溯   

问题描述:
给定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]

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

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

标签:动态规划   台阶求解   回溯   

原文地址:http://blog.csdn.net/watkinsong/article/details/47312867

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!