高效計算Fibonacci數

From: http://blog.csdn.net/jcwkyl/article/details/3677747

以前只知道使用遞歸或遞推的方法,最近在CSDN論壇上學到一種新的解法,在自己所知的幾個算法裏,它具有最好的運行效率。這種方法使用下面這個關於Fibonacci數的矩陣恆等式: 

這個算法就是根據這個恆等式,通過計算等式右邊的那個矩陣的n次方來計算第n個Fibonacci數。n次方的計算使用快速模冪算法,這樣計算n次方只用做log(n)次2*2矩陣的乘法,而每次乘法的計算時間是常量。所以,上述方法計算第n個Fibonacci數的時間複雜度是O(log(n))。相比之下,用遞歸來計算第n個Fibonacci的時間複雜度是O(Fn),是指數時間複雜度的。用遞推來計算,是O(n),然而當n很大時,n之於log(n),等於無窮大之於無窮小。
順便把關於Fibonacci的常用等式再總結一下:


From: http://tieba.baidu.com/p/1890441099

Fibonacci數是組合數學中非常重要的一個數列,它的遞推公式是:
  F(1)=F(2)=1
  F(n)=F(n-1)+F(n-2)
  當然,用這個公式來計算F(n)是非常慢的,當計算F(n)時需要從F(1)一直計算到F(n)。Fibonacci數列還滿足一些其他的公式,如:
  F(a+b+1)=F(a+1)*F(b+1)+F(a)*F(b)
  利用這個公式,可以加速Fibonacci數的計算。我們考慮同時計算F(2n+1)和F(2n),則按照上面的公式:
  F(2n+1)=F(n+1)*F(n+1)+F(n)*F(n)
  F(2n)=F(n+1)*F(n)+F(n)*F(n-1)=F(n+1)*F(n)+F(n)*(F(n+1)-F(n))
  這樣,F(2n+1)和F(2n)的計算變爲了F(n+1)和F(n)的計算,即下標變爲了原來的一半。重複利用這種方法,可以每次讓下標變爲原來的一半,總共需要大約log n次計算(以2爲底)。
  當n較大時,後面的方法就比直接的遞推要快得多,比如當n=1000000時,後面的方法大概需要20次計算,而直接遞推的方法大概需要1000000次計算


From: http://blog.sina.com.cn/s/blog_993d2542010143qw.html

現在的問題轉換爲求矩陣{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的矩陣,並且定義好矩陣的乘法以及乘方運算。當這些運算定義好了之後,剩下的事情就變得非常簡單。完整的實現代碼如下所示。

#include <cassert>

///////////////////////////////////////////////////////////////////////
// A 2 by 2 matrix
///////////////////////////////////////////////////////////////////////
struct Matrix2By2
{
      Matrix2By2
      (
            long long m00 = 0, 
            long long m01 = 0, 
            long long m10 = 0, 
            long long m11 = 0
      )
      :m_00(m00), m_01(m01), m_10(m10), m_11(m11) 
      {
      }

      long long m_00;
      long long m_01;
      long long m_10;
      long long m_11;
};

///////////////////////////////////////////////////////////////////////
// Multiply two matrices
// Input: matrix1 - the first matrix
//        matrix2 - the second matrix
//Output: the production of two matrices
///////////////////////////////////////////////////////////////////////
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);
}

///////////////////////////////////////////////////////////////////////
// The nth power of matrix 
// 1  1
// 1  0
///////////////////////////////////////////////////////////////////////
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)
      {
   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章