斐波那契数列

  • 格式:docx
  • 大小:5.30 MB
  • 文档页数:25

下载文档原格式

  / 38
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一句话先回答问题:因为斐波那契数列在数学和生活以及自然界中都非常有用。

下面我就尽我所能,讲述一下斐波那契数列。

一、起源和定义

斐波那契数列最早被提出是印度数学家Gopala,他在研究箱子包装物件长度恰好为1和2时的方法数时首先描述了这个数列。也就是这个问题:

有n个台阶,你每次只能跨一阶或两阶,上楼有几种方法?

而最早研究这个数列的当然就是斐波那契(Leonardo Fibonacci)了,他当时是为了描述如下情况的兔子生长数目:

•第一个月初有一对刚诞生的兔子

•第二个月之后(第三个月初)它们可以生育

•每月每对可生育的兔子会诞生下一对新兔子

•兔子永不死去

这个数列出自他赫赫有名的大作《计算之书》(没有维基词条,坑),后来就被广泛的应用于各种场合了。这个数列是这么定义的:

The On-Line Encyclopedia of Integer Sequences® (OEIS®)序号为A000045 - OEIS

(注意,并非满足第三条的都是斐波那契数列,卢卡斯数列(A000032 - OEIS)也满足这一特点,但初始项定义不同)

二、求解方法

讲完了定义,再来说一说如何求对应的项。斐波那契数列是编程书中讲递归必提的,因为它是按照递归定义的。所以我们就从递归开始讲起。

1.递归求解

int Fib(int n)

{

return n < 2 ? 1 : (Fib(n-1) + Fib(n-2));

}

这是编程最方便的解法,当然,也是效率最低的解法,原因是会出现大量的重复计算。为了避免这种情况,可以采用递推的方式。

2.递推求解

int Fib[1000];

Fib[0] = 0;Fib[1] = 1;

for(int i = 2;i < 1000;i++) Fib[i] = Fib[i-1] + Fib[i-2];

递推的方法可以在O(n)的时间内求出Fib(n)的值。但是这实际还是不够好,因为当n很大时这个算法还是无能为力的。接下来就要来讲一个有意思的东西:矩阵。

3.矩阵递推关系

学过代数的人可以看出,下面这个式子是成立的:

不停地利用这个式子迭代右边的列向量,会得到下面的式子:

这样,问题就转化为如何计算这个矩阵的n次方了,可以采用快速幂的方法。快速幂_百度百科是利用结合律快速计算幂次的方法。比如我要计算,我们知道

,而可以通过来计算,而可以通过计算,以此类推。通过这种方法,可以在O(lbn)的时间里计算出一个数的n次幂。快速幂的代码如下:

int Qpow(int a,int n)

{

int ans = 1;

while(n)

{

if(n&1) ans *= a;

a *= a;

n >>= 1;

}

return ans;

}

将上述代码中的整型变量a变成矩阵,数的乘法变成矩阵乘法,就是矩阵快速幂了。比如用矩阵快速幂计算斐波那契数列:

#include

#include

using namespace std;

const int MOD = 10000;

struct matrix//定义矩阵结构体

{

int m[2][2];

}ans, base;

matrix multi(matrix a, matrix b)//定义矩阵乘法

{

matrix tmp;

for(int i = 0; i < 2; ++i)

{

for(int j = 0; j < 2; ++j)

{

tmp.m[i][j] = 0;

for(int k = 0; k < 2; ++k)

tmp.m[i][j] = (tmp.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD;

}

}

return tmp;

}

int fast_mod(int n) // 求矩阵 base 的 n 次幂

{

base.m[0][0] = base.m[0][1] = base.m[1][0] = 1;

base.m[1][1] = 0;

ans.m[0][0] = ans.m[1][1] = 1; // ans 初始化为单位矩阵

ans.m[0][1] = ans.m[1][0] = 0;

while(n)

{

if(n & 1) //实现 ans *= t; 其中要先把 ans赋值给 tmp,然后用 ans = tmp * t ans = multi(ans, base);

base = multi(base, base);

n >>= 1;

}

return ans.m[0][1];

}

int main()

int n;

while(scanf("%d", &n) && n != -1)

{

printf("%d\n", fast_mod(n));

}

return 0;

}

4.通项公式

无论如何,对于一个数列,我们都是希望可以建立与n的关系,也就是通项公式,而用不同方法去求解通项公式也是很有意思的。

(1)构造等比数列

设,

化简得,

比较系数得,

解得,

由于

故有,设.则有

,设,

解得,即{}是等比数列。这样就有

到了现在,把上述解出的结果全部带入上式,稍作变形,我们就可以写出斐波那契数列的通项公式了