程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> fibonacci數列和跳台階問題

fibonacci數列和跳台階問題

編輯:C++入門知識

首先百度之後知道,fibonacci數列其實在科學中有著廣泛的應用,下面一句話引子百度百科:在現代物理、准晶體結構、化學等領域,斐波納契數列都有直接的應用。
了解fibonacci數列的人都知道它的推到公式:
   0                       n=0
f(n)=1                       n=1
         f(n-1)+f(n-2)   n>=2
有時候遇到的問題是如何求解fibonacci數列的各項的值,我記得有兩種方法,就是遞歸方法和應用循環的方法。下面給出兩種程序的代碼:
[cpp] 
#include<stdio.h> 
int fibonacci_recursion(int n) 
{//遞歸算法 
    int result[2]={0,1}; 
    if(n<2) 
        return result[n]; 
    else 
        return fibonacci_recursion(n-1)+fibonacci_recursion(n-2); 

int fibonacci_non_recursion(int n) 
{//非遞歸算法 
    int result[2]={0,1}; 
    if(n<2) 
        return result[n]; 
    int i; 
    int fa=0,fb=1,fc; 
    for(i=1;i<n;i++) 
    { 
        fc=fa+fb; 
        fa=fb; 
        fb=fc; 
    } 
    return fc; 

void main() 

    int n; 
    printf("input n value:"); 
    scanf("%d",&n); 
    printf("%d\n",fibonacci_recursion(n)); 
    printf("%d\n",fibonacci_non_recursion(n)); 

上面的兩個方法都是在O(N)的時間內得到解,但是在csdn的論壇上看到有人說,可以再O(logn)時間內求得fibonacci數列的第n項值,於是google了一下,找到了一篇博文,的確可以在O(logn)內求解。
有一個數學公式:{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1。
(注:{f(n+1), f(n), f(n), f(n-1)}表示一個矩陣。在矩陣中第一行第一列是f(n+1),第一行第二列是f(n),第二行第一列是f(n),第二行第二列是f(n-1)。)
下面就來證明一下這個公式的正確性:fibonacci的第0項為0,第一項和第二項分別是1,所以有公式{1,1,1,0},然後第三項為2,那麼有公式{2,1,1,1},此時k=3,則計算第一個公式的平方結果是{2,1,1,1},結果正對,假設k=n-1時,公式成立,就有{f(n-1), f(n-2), f(n-2), f(n-3)} ={1, 1, 1,0}n-2
由fibonacci數列的遞推式可以得到{f(n),f(n-1),f(n-1),f(n-2)}={f(n-1)+f(n-2),f(n-1),f(n-2)+f(n-3),f(n-2)},因為計算的原因,公式中第二項和第四項不用代換,可以看出,這個結果就是{f(n-1), f(n-2), f(n-2), f(n-3)}與{1,1,1,0}相乘的結果。故原式得證。
如果簡單第從0開始循環,n次方將需要n次運算,並不比前面的方法要快。但我們可以考慮乘方的如下性質:
        /  an/2*an/2                      n為偶數時
an=
        \  a(n-1)/2*a(n-1)/2            n為奇數時
要求得n次方,我們先求得n/2次方,再把n/2的結果平方一下。如果把求n次方的問題看成一個大問題,把求n/2看成一個較小的問題。這種把大問題分解成一個或多個小問題的思路我們稱之為分治法。這樣求n次方就只需要logn次運算了。
實現這種方式時,首先需要定義一個2×2的矩陣,並且定義好矩陣的乘法以及乘方運算。當這些運算定義好了之後,剩下的事情就變得非常簡單。完整的實現代碼如下所示。
[cpp] 
<span style="font-family:Simsun;">#include<stdio.h> 
#include<assert.h> 
struct Matrix2By2 

    int m_00; 
    int m_01; 
    int m_10; 
    int m_11; 
    Matrix2By2(int m00=0,int m01=0,int m10=0,int m11=0):m_00(m00),m_01(m01),m_10(m10),m_11(m11) 
    { 
    } 
}; 
Matrix2By2 MatrixMultiply(const Matrix2By2& matrix1,const Matrix2By2& matrix2) 

    return Matrix2By2( 
            matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10, 
            matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11, 
            matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10, 
            matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11); 

Matrix2By2 MatrixPower(unsigned int n) 

    assert(n>0); 
    Matrix2By2 matrix; 
    if(n==1) 
        matrix=Matrix2By2(1,1,1,0); 
    else if(n%2==0) 
    { 
        matrix=MatrixPower(n/2); 
        matrix=MatrixMultiply(matrix,matrix); 
    } 
    else if(n%2==1) 
    { 
        matrix = MatrixPower((n - 1) / 2); 
        matrix = MatrixMultiply(matrix, matrix); 
        matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0)); 
    } 
    return matrix; 

int fibonacci_solution(unsigned int n) 

      int result[2] = {0, 1}; 
      if(n < 2) 
            return result[n]; 
 
      Matrix2By2 PowerNMinus2 = MatrixPower(n - 1); 
      return PowerNMinus2.m_00; 

void main() 

    unsigned int n; 
    printf("input n value:"); 
    scanf("%d",&n); 
    printf("%d\n",fibonacci_solution(n)); 
}</span> 
運行,能得到正確的結果。就像題目所說,給我fibonacci在我們計算機中的一個應用吧,就是跳台階的問題。給定n個台階,有兩種選擇,就是一次可以跳一個台階,還有是一次可以跳兩個台階。求總共有多少總跳法,並分析算法的時間復雜度。把n級台階時的跳法看成是n的函數,記為f(n)。當n>2時,第一次跳的時候就有兩種不同的選擇:一是第一次只跳1級,此時跳法數目等於後面剩下的n-1級台階的跳法數目,即為f(n-1);另外一種選擇是第一次跳2級,此時跳法數目等於後面剩下的n-2級台階的跳法數目,即為f(n-2)。因此n級台階時的不同跳法的總數f(n)=f(n-1)+(f-2)。
    我們把上面的分析用一個公式總結如下:
        /  1                             n=1
f(n)=      2                          n=2
        \  f(n-1)+(f-2)            n>2
如果有三種選擇就是一次可以分別跳1,2,3,次的話,這個遞推式就可以寫成:f(n)=f(n-1)+f(n-2)+f(n-3).

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved