動態規划之機器人行走問題


1. 問題描述:機器人一次可以走1m,2m或3m,那么機器人走n米有多少種走法?

2. 問題分析:

  用a(n)來表示機器人走n米的走法總數,

  那么,n<=0, a(n)=0;

  n==1, a(n)=1;

  n==2, a(n)=2: 1+1, 2;

  n==3, a(n)=4: 1+1+1, 1+2, 2+1, 3;

  但如此枚舉下去不是辦法,那么我們換個角度思考: 機器人走完全程的前一次運動時(注:機器人一次可以走1m,2m或3m),它離終點還有多遠:

  1. 還有1m, 進行一次走1m的運動就能到達終點。

  2. 還有2m, 進行一次走2m的運動就能到達終點。

  3. 還有3m, 進行一次走3m的運動就能到達終點。

  這樣一來的話,我們可以知道:a(n)=a(n-1)+a(n-2)+a(n+3), 即走n米的走法總數 = 走n-1米的走法總數 + 走n-2米的走法總數 + 走n-3米的走法總數

 

C語言實現:(動態規划——自底向上(迭代法))

// Hello, i'm 九院干干

/*
++++++++++++++++++++++++++++++++++++++++ + 關鍵點:a(n) = a(n-1) + a(n-2) + a(n-3) + 此版本借助了輔助n個空間,說明該算法還 + 可以進化 + 時間復雜度O(n), 空間復雜度O(n) ++++++++++++++++++++++++++++++++++++++++ */ #include <stdio.h> #include <stdlib.h> #define size 100 int RobotWalk(int n,int a[]) { int i,x; if(n<=0) return 0; if(n==1 ||n==2) return n; if(n==3) return 4; a[1] = 1; a[2] = 2; a[3] = 4; for(i=4; i<=n; i++) a[i] = a[i-1] + a[i-2] + a[i-3]; // 計算從小到大向前推進,計算a[4]->a[5]->...->a[n] return a[n]; } void main() { int n, KindSum; int a[size]; printf("請輸入機器人要走的路程總長度:"); scanf("%d",&n); KindSum = RobotWalk(n,a); printf("機器人的走法有%d種\n", KindSum); system("pause"); }

運行結果:

 

進一步優化:(上面的算法的空間復雜度為O(n),改進后,只需3個輔助空間) 

 C語言實現:

/*
+++++++++++++++++++++++++++++++++++++++++
+
+ 這個算法版本就是利用3個存儲單元,存儲計算米數
+ 增加一個長度的三個歷史走法總數。
+ 
+++++++++++++++++++++++++++++++++++++++++
*/



#include <stdio.h>
#include <stdlib.h>

int RobotWalk(int n)
{
    int i, count, temp;
    int a[3] = {1,2,4};
    if(n<=0) return 0;
    if(n==1) return a[0];
    if(n==2) return a[1];
    if(n==3) return a[2];

    count= 0;

/*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+下面這個for循環是關鍵,count用來計數,以使數組a中每次只更新最老的歷史數據,
+ 即最新的數據替換最老的數據,例如最先更新最老數據a[0],a[0]成為最新數據;之后
+ 更新最老數據a[1], a[1]成為最新數據;然后更新最老數據a[2],a[2]成為最新數據。
+ 此過程不斷循環,直到計算出走n米的走法總數。
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/


    for(i=4; i<=n; i++)
    {
        temp = a[2] + a[1] + a[0];
        a[count] = temp;
        count = (count+1)%3;   //循環更新count,使其取值為{0,1,2},對應於數組a的下標
    }
    return temp;
}

void main()
{
    int n, KindSum;
    printf("請輸入機器人要走的路程總長度:");
    scanf("%d",&n);
    KindSum = RobotWalk(n);
    printf("機器人的走法有%d種\n", KindSum);
    system("pause");
}

 

運行結果:

 

除了運用自底向上的思維,當然還可以使用自頂向下的解法。

 

C語言實現:(動態規划——自頂向下(遞歸的方式))

// Hello, i'm 九院干干

/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + 該算法是采用遞歸的思想,但需要記錄計算過的子問題,以避免重復計算子問題。 + 因此,若是碰到曾經計算過得問題就直接返回其解。 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include <stdio.h> #include <stdlib.h> #define size 1000 int RobotWalk(int n, int a[]) { if(a[n]!=0) return a[n]; //返回計算過的子問題的解 if(n<=0) return 0; if(n==1 || n==2) return n; if(n==3) return 4; else { a[n] = RobotWalk(n-1,a) + RobotWalk(n-2,a) + RobotWalk(n-3,a); // 遞歸實現 a[n] = a[n-1]+a[n-2]+a[n-3] return a[n]; } } void main() { int n, KindSum; int a[size] = {0}; //對數組元素初始化為0 printf("請輸入機器人要走的路程總長度:"); scanf("%d",&n); KindSum = RobotWalk(n,a); printf("機器人的走法有%d種\n", KindSum); system("pause"); }

 

運行結果:

 

 

Python實現:(自底向上 / 迭代法):

# Hello, i'm 九院干干

#
+++++++++++++++++++++++++++++++++++++++++++++++ # 此算法的輔助空間為3,則空間復雜度可以看成O(1) # 自底向上(迭代法) #++++++++++++++++++++++++++++++++++++++++++++++++ def RobotWalk(n): a= [1,2,4] if n<=0 : return 0 if n==1 or n==2 : return n if n==3 : return 4 else: count = 0 for i in range(4,n+1): temp = a[2] + a[1] +a[0] a[count] = temp count = (count+1)%3 return a[count-1] if __name__ == '__main__': n = int(input("請輸入機器人要行走的總路程:")) KindSum = RobotWalk(n) print("機器人的走%d米的走法總數為:%d" %(n,KindSum))

運行結果:

 

Python實現:(動態規划——自頂向下(遞歸的方式))

 

def RobotWalk(n,a):
    if a[n]!=0 : return a[n]
    if n<=0: return 0
    if n==1 or n==2: return n
    if n==3: return 4
    else:
        for i in range(4,n+1):
            a[n] = RobotWalk(n-1,a) + RobotWalk(n-2,a) + RobotWalk(n-3,a)

        return a[n]


if __name__ == '__main__':

    n = int(input("請輸入機器人要行走的總路程:"))
    a = (n+1)*[0]
    KindSum = RobotWalk(n,a)
    print("機器人的走%d米的走法總數為:%d" %(n,KindSum))

 

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM