斐波那契数列 矩阵求法 优化

来源:互联网 发布:淘宝无法开店 编辑:程序博客网 时间:2024/05/22 04:49

在做编程题目的时候经常会遇到“斐波那契数列”相关的题目,尤其在做OJ中。下面说一些方法:

  (一)递归

  递归是最慢的会发生重复计算,时间复杂度成指数级。


long long fac(int n){  if(n==1)   return 1;  else if(n==2)   return 2;  else    return fac(n-1)+fac(n-2);}

  (二)循环

  利用临时变量来保存中间的计算过程,加快运算。


long long fac(int n){    long long a=1,b=2,c;    if(n==1)    return 1;    else if(n==2)   return 2;    else    {        for(int i=3;i<=n;i++)        {            c=a+b;   a=b;   b=c;        }    }    return b;}


  (三)矩阵乘法+空间换时间(减少乘法,取模运算)

   数列的递推公式为:f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)(n>=3)

   用矩阵表示为:

  进一步,可以得出直接推导公式:

   由于矩阵乘法满足结合律,在程序中可以事先给定矩阵的64,32,16,8,4,2,1次方,加快程序的执行时间。(有些题目需要取模运算,也可以事先进行一下)。给定的矩阵次幂,与二进制有关是因为,如下的公式存在解满足Xi={01}: 

 

为了保证解满足 Xi={0或1},对上述公式的求解从右向左,即求解顺序为Xn,Xn-1,Xn-2,....,X1,X0。

完整代码实现如下:

#include <stdio.h>#include <stdlib.h>#include <math.h>/**先用一个数组保存1 11 0矩阵n次幂的值,这样可以提高运行效率*/long long fac_tmp[7][4]={    {1,1,1,0},///1  0    {2,1,1,1},///2  1    {5,3,3,2},///4  2    {34,21,21,13},///8 3    {1597,987,987,610},///16 4    {24578,78309,78309,46269},///32 5    {77565,57723,57723,19842} ///64 6};int mod=100000;/**计算第k个斐波那契数,用来求数组void get(int k)  {        for(int i=k; i>=0; --i)        {            a=(t00*fac_tmp[0][0]+t01*fac_tmp[0][2])%mod;            b=(t00*fac_tmp[0][1]+t01*fac_tmp[0][3])%mod;            c=(t10*fac_tmp[0][0]+t11*fac_tmp[0][2])%mod;            d=(t10*fac_tmp[0][1]+t11*fac_tmp[0][3])%mod;            t00=a;            t01=b;            t10=c;            t11=d;        }        printf("%d:\n",k+2);        printf("%I64d,%I64d,%I64d,%I64d\n",a,b,c,d);        a=(t00*2+t01*1)%mod;        return a;    } }**/void fac(int k){    int i,ok=k;    long long t00=1,t01=1,t10=1,t11=0;    long long a=1,b=1,c=1,d=0;    if(k==1) a=1;    else if(k==2) a=2;    else    {        k=k-3;        if(k>64)        {            for(i=k; i>=64; i-=64)            {                a=(t00*fac_tmp[0][0]+t01*fac_tmp[0][2])%mod;                b=(t00*fac_tmp[0][1]+t01*fac_tmp[0][3])%mod;                c=(t10*fac_tmp[0][0]+t11*fac_tmp[0][2])%mod;                d=(t10*fac_tmp[0][1]+t11*fac_tmp[0][3])%mod;                t00=a;                t01=b;                t10=c;                t11=d;            }        }        i=5;        while(i>=0)        {            if(k>=(long long)pow(2,i))            {                a=(t00*fac_tmp[i][0]+t01*fac_tmp[i][2])%mod;                b=(t00*fac_tmp[i][1]+t01*fac_tmp[i][3])%mod;                c=(t10*fac_tmp[i][0]+t11*fac_tmp[i][2])%mod;                d=(t10*fac_tmp[i][1]+t11*fac_tmp[i][3])%mod;                t00=a;                t01=b;                t10=c;                t11=d;                k=k-(int)pow(2,i);            }            i--;        }        a=(t00*2+t01*1)%mod;    }    printf("Fab(%d) = %I64d\n",ok,a);}int main(){    int k;    while(scanf("%d",&k)!=EOF)    {        fac(k);        printf("\n");    }    return 0;} 

转自 :旭东的博客

1 0
原创粉丝点击