



意大利数学家斐波那契(Fibonacci)在他的著作《计算之书》里提出了一个问题:“假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生下一对小兔,一年内没有发生死亡,那么一对刚出生的兔子,在一年内繁殖成多少对兔子?”由该繁衍规律得到的每个月兔子的数量组成了Fibonacci数列,也称为“兔子数列”,如图2.2所示。
图2.2 兔子数列
Fibonacci数列增长速度非常快。19世纪中期的澳大利亚野兔成灾事件体现了真实版的“兔子数列”惊人的增长速度。当时英国人为了满足自己的狩猎爱好,把欧洲野兔引入澳大利亚。由于澳大利亚气候温暖、牧草丰富,为兔子提供了良好的生存条件,加上澳大利亚本土缺乏猛禽、黄鼠狼等兔子的天敌,兔子开启了斐波那契数列式的增长,当时澳大利亚的生态遭到了严重破坏,继而开始了人兔大战……
Fibonacci数列的前几项为1、1、2、3、5、8、13、21、34、55、89。仔细观察这个数列发现,第1项和第2项为1,此后每一项都是前2项的和。
在图2.2中,为什么从第3个月开始,每个月的兔子对数等于前两个月兔子对数之和?这是因为,每个月的兔子对数包括大兔子对数和小兔子对数,上个月每一对兔子无论是大兔子还是小兔子,到了这个月一定是大兔子;而上上个月每一对兔子无论是大兔子还是小兔子,到了这个月一定会生下一对小兔子。
输入 n 值,输出Fibonacci数列的第 n 项,该数列前5项为1、1、2、3、5。
输入占一行,为 n 的值,1≤ n ≤40。
输出占一行,为Fibonacci数列第 n 项的值。
注意,Fibonacci数列增长速度非常快,第46项为1836311903,第47项就超出int型数据的取值范围了。
可以采用递推方式递推出Fibonacci数列的每一项。如图2.3所示,用 f 1 , f 2 , f 3 表示连续的3项,每一轮递推, f 3 = f 1 + f 2 ,就得出新的一项,然后更新 f 1 和 f 2 的值, f 1 更新为 f 2 , f 2 更新为 f 3 ;下一轮循环,因为 f 1 和 f 2 的值已经更新了,所以再递推出 f 3 ,又是新的一项。
图2.3 采用递推方式求Fibonacci数列每一项(1)
在图2.3中, f 1 , f 2 , f 3 就像一只蠕虫的三节一样,蠕虫每一轮向前爬一格。爬一格后, f 1 就对应到之前 f 2 的位置, f 2 就对应到之前 f 3 的位置。
代码如下:
#include <iostream>
using namespace std;
int main( )
{
int n; cin >>n;
int f1 = 1, f2 = 1, f3; // f1和f2的初始值均为1
if(n == 1 or n == 2) cout <<1 <<endl;
else{
for(int i=3; i<=n; i++){ // 递推出第3~n项
f3 = f1 + f2;
f1 = f2; // 这行代码不能和下面一行代码交换位置
f2 = f3;
}
cout <<f3 <<endl;
}
return 0;
}
其实也可以用两个变量 f 1 和 f 2 实现Fibonacci数列的递推, f 1 和 f 2 表示连续的两项,如图2.4所示。为了递推出新的一项,有 f 2 = f 1 + f 2 ,此后 f 1 要更新为之前 f 2 的值,所以要事先用临时变量 t 保存 f 2 的值,即 t = f 2 ,最后才能把 t 的值赋给 f 1 ,即 f 1 = t 。这3条关键的代码不能交换顺序。
图2.4 采用递推方式求Fibonacci数列每一项(2)
代码如下:
#include <iostream>
using namespace std;
int main( )
{
int n; cin >>n;
int f1 = 1, f2 = 1, t; // f1和f2的初始值均为1
if(n == 1 or n == 2) cout <<1 <<endl;
else{
for(int i=3; i<=n; i++){ // 递推出第3~n项
t = f2; //这3行代码不能交换顺序
f2 = f1 + f2;
f1 = t;
}
cout <<f2 <<endl;
}
return 0;
}