動態規劃-樓梯問題

一、問題描述

有一樓梯共M級,剛開始時你在第一級,若每次只能跨上一級或二級,要走上第M級,共有多少種走法?java

輸入輸出描述
Input
輸入數據首先包含一個整數N,表示測試實例的個數,而後是N行數據,每行包含一個整數M(1<=M<=40),表示樓梯的級數。
Output
對於每一個測試實例,請輸出不一樣走法的數量
示例:算法

Sample Input
2
2
3
Sample Output
1
2

二、思路分析

利用動態規劃(DP,dynamic programming)思想,簡單來講:大事化小小事化了測試

假設10級,考慮只差最後一步到10級,一步走1階或2階,只有兩種可能:到9階和到8階。
若是到9階的走法有X種,到8階的走法有Y種,那麼,總走法=X+Y。
即:F(10)=F(9)+F(8)
同理,F(9)=F(8)+F(7),F(8)=F(7)+F(6),這樣問題能夠從10階到 [9和8] 階,再到 [9和8] 拆開的階,這樣往下,分階段將問題簡化。code

尋找基準或者初始解:當爲F(2)和F(1)時,前者有兩種走法(1+1,2),後者有一種走法(1)。
即:①F(2)=2,F(1)=1。再加上②F(10)=F(9)+F(8),遞歸

獲得三個動態規劃的概念:
最優子結構】:F(9)和F(8),是F(10)的最優子結構
邊界】:F(1)和F(2)是問題的邊界,沒法再簡化/拆解
狀態轉移方程】:F(10)=F(9)+F(8),上下階段的關係get

遞歸公式:F(n)=F(n-1)+F(n-2),實爲斐波那契數列的遞歸公式。class

三、程序實現

首先用遞歸進行實現,與動態規劃作比較。前者代碼簡潔,但執行效率不如後者。效率

1)遞歸

int getWays(int n){
    if(n<1) return 0;
    if(n==1) return 1;
    if(n==2) return 2;
    return getWays(n-1)+getWays(n-2)
}

2)動態規劃

從底到上推導:
F(1)=1,F(2)=2,
F(3)=F(2)+F(1)=1+2
F(4)=F(3)+F(2)=3+2
每次迭代,只保留以前的兩個狀態,便可推導新的狀態。import

源程序:程序

import java.util.Scanner;

/**
 * Input:輸入數據首先包含一個整數N,表示測試實例的個數,而後是N行數據,每行包含一個整數M(1<=M<=40),表示樓梯的級數。
 * Output:對於每一個測試實例,請輸出不一樣走法的數量
 */
public class DPSumsung {

    public static int getWays(int n) {
        if(n<1) return 0;
        if(n==1) return 1;
        if(n==2) return 2;
        
        int a=1;
        int b=2;
        int next=0;
        for(int i=3;i<=n;i++) {
            next=a+b;
            a=b;
            b=next;
        }
        return next;
    }
    
    public static void main(String[] args) {

        Scanner sc=new Scanner(System.in);
        int count=sc.nextInt();
        int[] ways=new int[count];
        int i=0;
        int n=sc.nextInt();
        while(n>=1&&n<=40) {         
            ways[i++]=DPSumsung.getWays(n);
            if(i>=count)
                break;
            n=sc.nextInt();
        }
        for(int temp:ways) {
            System.out.println(temp);
        }
        sc.close();
    }
}

四、算法分析

時間複雜度爲O(N),空間複雜度爲O(1)。

相關文章
相關標籤/搜索