您的位置:首页 > 其它

求斐波那契数列的多种方法(有矩阵(附好模板))

2017-08-09 21:31 288 查看
f[1]=1; f[2]=2; f
=f[n-1]+f[n-2];

(1)递推

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


(2) 循环

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


(3)矩阵乘法(空间换时间)【可取模哦】

数列的递推公式由矩阵乘法表示为



进一步,可得



那我们如何计算[1110]的(n−2)次方?



假设计算A的n次幂:

二阶矩阵的乘法满足结合律:A(BC)=(AB)C

法一:

令n=N/2;

1.若n为偶数,则A^N=A^n * A^n

2.若n为奇数,则A^N=A^n * A^n * A

举例:A^6=A^3 * A^3

A^7=A^3 * A^3 * A

//使用模板前需先分析f[2]=1还是2!!!!!!!!!!!!!!!!!!!!!(这里f[2]=1)
void multiply(int c[2][2],int a[2][2],int b[2][2],int mod)
{
int tmp[4];
tmp[0]=a[0][0]*b[0][0]+a[0][1]*b[1][0];
tmp[1]=a[0][0]*b[0][1]+a[0][1]*b[1][1];
tmp[2]=a[1][0]*b[0][0]+a[1][1]*b[1][0];
tmp[3]=a[1][0]*b[0][1]+a[1][1]*b[1][1];
c[0][0]=tmp[0]%mod;
c[0][1]=tmp[1]%mod;
c[1][0]=tmp[2]%mod;
c[1][1]=tmp[3]%mod;
}//计算矩阵乘法,c=a*b

int fibonacci(int n,int mod)//mod表示数字太大时需要模的数
{
if(n==0)return 0;
else if(n<=2)return 1;//这里表示第0项为0,第1,2项为1

int a[2][2]={{1,1},{1,0}};
int result[2][2]={{1,0},{0,1}};//初始化为单位矩阵
int s;
n-=2;
while(n>0)
{
if(n%2 == 1)
multiply(result,result,a,mod);
multiply(a,a,a,mod);
n /= 2;
}//二分法求矩阵幂
s=(result[0][0]+result[0][1])%mod;//结果
return s;
}


法二:

“二进位为1需要乘,为0不需要乘”

以计算A^6为例:

A^6=A^4 * A^2

将6转换成二进制:110

第2位为1,需要乘,乘2^2(即A^4); 第1位还为1,需要乘,乘2^1(即A^2); 第0位为0,不需要乘。

即:若需要乘,则乘2^pos.

十进制7 = 二进制 111

则A^7=A^4∗A^2∗A^1

////使用模板前需先分析f[2]=1还是2!!!!!!!!!!!!!!!!!!!!!(这里f[2]=2)
///求解fac(n)%100000,其中n为大于等于3的正整数
#include<stdio.h>
#include<math.h>
long long fac_tmp[6][4]={   ///存放矩阵次幂
///位置:00 01 10 11
{24578,78309,78309,46269},   ///32次幂%100000
{1597,987,987,610},  ///16次幂%100000
{34,21,21,13},   ///8次幂%100000
{5,3,3,2},   ///4次幂%100000
{2,1,1,1},   ///2次幂%100000
{1,1,1,0},   ///1次幂%100000
};
void fac(int);

int main()
{
int n;
scanf("%d",&n);
fac(n);
return 1;
}

void fac(int k) ///k>=3
{
int i;
long long t00=1,t01=1,t10=1,t11=0;  ///表示矩阵的1次幂
long long a,b,c,d;
k=k-3;  ///公式中是n-2次幂,(t00,t01,t10,t11)表示1次幂。所以一共减3次
for(i=k;i>=32;i=i-32)   ///对于大于等于32的k;
{
a=(t00*fac_tmp[0][0]+t01*fac_tmp[0][2])%100000;
b=(t00*fac_tmp[0][1]+t01*fac_tmp[0][3])%100000;
c=(t10*fac_tmp[0][0]+t11*fac_tmp[0][2])%100000;
d=(t10*fac_tmp[0][1]+t11*fac_tmp[0][3])%100000;
t00=a;  t01=b;  t10=c;t11=d;
}

i=4;
while(i>=0)    ///对于小于32的k(16,8,4,2,1);
{
if(k>=(long long)pow(2,i))  ///如果k大于某一个2的次幂
{

a=(t00*fac_tmp[5-i][0]+t01*fac_tmp[5-i][2])%100000; ///(5-i):矩阵的2的i次幂在数组fac_tmp中的位置为fac_tmp[5-i]
b=(t00*fac_tmp[5-i][1]+t01*fac_tmp[5-i][3])%100000;
c=(t10*fac_tmp[5-i][0]+t11*fac_tmp[5-i][2])%100000;
d=(t10*fac_tmp[5-i][1]+t11*fac_tmp[5-i][3])%100000;
t00=a;  t01=b;  t10=c;t11=d;
k=k-(int)pow(2,i);
}
i--;
}

a=(t00*2+t01*1)%100000;
printf("%lld\n",a);
}


(4) 直接上公式……

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  斐波那契