[1]递归法
int Fib(int index) { if(index<1) { return-1; } if(index==1|| index==2) { return1; } return Fib1(index-1)+Fib1(index-2); }
int Fib(int index) { if(index<1) { return-1; } int a1=1,a2=1,a3=1; for(int i=0;i<index-2;i++) { a3=a1+a2; a1=a2; a2=a3; } return a3; }
Fibonacci 数列的递推公式是二次递推式,二次递推式的通用解法是转换为如下形式:
转换后的一次递推式很容易生成联合方程,求出通项式,以下是a0=0, a1=1时的 Fibonacci 通项式:
int Fib(int n) { double gh5=sqrt((double)5); return (pow((1+gh5),n)-pow((1-gh5),n))/(pow((double)2,n)*gh5); }
Fibonacci 数列可以转化为一个等价矩阵,其通项为:
利用乘法的高效性提升性能,一般用于较大的Fibonacci数,因为在int范围内,其性能和代码简洁性不如递推法。
乘法的好处是,如F(90),利用递推,需要90次循环。但利用幂乘,将A^90拆分为A^90=A^64 * A^16 * A^8 * A^2,而A^64、A^16、A^8可以依次由A^2计算得出。只用几次乘法即可达到90次循环递推的效果,n越大,加速性越好。
矩阵乘法的实现代码比较简单,不再给出具体代码。只讨论其中的拆分子步骤。
n的拆分有多种, 甚至无需拆分,直接分割递归也可以。代码如下:
//来自 http://www.2cto.com/kf/201208/148361.html
Matrix power1 (LLD p) //矩阵幂 A^k { Matrix tp = a2 ; Matrix tr = tmp ; while (p) { if (p&1) { tr = Multi (tr, tp) ; p -- ; continue ; } tp = Multi (tp, tp) ; p >>= 1 ; } return tr ; } Matrix Multi (Matrix a, Matrix b) //两矩阵相乘 { Matrix c ; for (int i = 0; i < 2;i ++) for (int j = 0; j < 2; j ++) { c.mat[i][j] = 0 ; for (int k = 0; k < 2; k ++) c.mat[i][j] += (LLD)a.mat[i][k]*b.mat[k][j] ,c.mat[i][j] %= M ; //矩阵相乘时,需要防止溢出 } return c ; }
将任意正整数拆分为2的幂的和,如90=2^6+2^4+2^3+2^1.
拆分算法各种各样,下面给出我的二幂拆分法:基于位操作的二幂拆分
这种方法的核心是找到幂指数,下面是找幂指数的代码(核心是分离数的bit位)
typedef struct _x //_x is a tag of type x, generally used in the body for self pointer { unsigned bits[8*sizeof(unsigned)]; //sizeof operator returns the number of bytes of type unsigned } x; //define struct x x SplitInt(unsigned value) { x bitArray; //used to store the bit value of n //get each bit from right const unsigned MASK = 1; //MASK = 00000000 00000000 00000000 00000001 for(unsigned i=8*sizeof(unsigned)-1; i>=0; i--) { bitArray.bits[i] = (value & MASK ? 1 : 0 ); //if value&MASK is 0(false), set the bit to 0;else if it is not 0(true), set the bit to 1; value >>= 1; //shift value left by 1; } return bitArray; } 更一般地,分离数的bit位代码模板如下(核心代码只有一行,即可分离所有位): void func_SplitInt(unsigned value) { for(unsigned i=8*sizeof(unsigned)-1; i>=0; i--,value>>=1) cout<<(value & 1 ?1:0)<<endl; }
#include <cstdio> #include <iostream> #include <cstdlib> using namespace std; //求矩阵a的n次幂的函数 long long * Matrix(long long *a,int n) { long long *result = (long long *)malloc(sizeof(long long)*4); long long *finnal = (long long *)malloc(sizeof(long long)*4); //如果n等于1的话,则直接返回矩阵a,毕竟,一次幂就不必求了。 if(n==1) return a; //先求出矩阵的n/2次幂 long long *CurMatrix = Matrix(a,n/2); //两个矩阵的n/2次幂相乘得到矩阵的n次幂 result[0] = CurMatrix[0]*CurMatrix[0]+CurMatrix[1]*CurMatrix[2]; result[1] = CurMatrix[0]*CurMatrix[1]+CurMatrix[1]*CurMatrix[3]; result[2] = CurMatrix[2]*CurMatrix[0]+CurMatrix[3]*CurMatrix[2]; result[3] = CurMatrix[2]*CurMatrix[1]+CurMatrix[3]*CurMatrix[3]; //如果n为奇数的话,则(n/2)会少一位,补回来。a = a^(n/2)*a^(n/2) * a; if(n%2==1) { finnal[0] = result[0]*a[0]+result[1]*a[2]; finnal[1] = result[0]*a[1]+result[1]*a[3]; finnal[2] = result[2]*a[0]+result[3]*a[2]; finnal[3] = result[2]*a[1]+result[3]*a[3]; } //如果n为偶数的话,n/2还是n/2 else finnal = result; return finnal; } int main(void) { long long a[4]; int n; cin>>n; //矩阵按一位数组设置,t[0]即为febonacci(n) a[0] = 1; a[1] = 1; a[2] = 1; a[3] = 0; long long *t = Matrix(a,n-1); cout<<t[0]<<endl; return 0; }