假定你有一雄一雌一对刚出生的兔子,它们在长到一个月大小时开始交配,在第二月结束时,雌兔子产下另一对兔子,过了一个月后它们也开始繁殖,如此这般持续下去。每只雌兔在开始繁殖时每月都产下一对兔子,假定没有兔子死亡,在一年后总共会有多少对兔子?
在一月底,最初的一对兔子交配,但是还只有1对兔子;在二月底,雌兔产下一对兔子,共有2对兔子;在三月底,最老的雌兔产下第二对兔子,共有3对兔子;在四月底,最老的雌兔产下第三对兔子,两个月前生的雌兔产下一对兔子,共有5对兔子;……如此这般计算下去,兔子对数分别是:1, 1, 2, 3, 5, 8, 13, 21, 34, 55,89, 144, ...看出规律了吗?从第3个数目开始,每个数目都是前面两个数目之和。这就是著名的斐波那契(Fibonacci)数列。
C 编程解决如下:
#includeint Fib(int n) { if (n == 1 || n == 2) return 1; else return Fib(n-1) + Fib(n-2); } int main() { int wait; printf("一年可以有 %d 对兔子n", Fib(12)); scanf("%d",&wait); return 0; }
有许多相关问题:
有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
答:这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种方法……所以,1,2,3,5,8,13……登上十级,有89种。
数列中相邻两项的前项比后项的极限是多少,就是问,当n趋于无穷大时,F(n)/F(n+1)的极限是多少?
答:这个可由它的通项公式直接得到,极限是(-1+√5)/2,这个就是所谓的黄金分割点,也是代表大自然的和谐的一个数字。
Fibonacci数列的数学表达式就是:F(n) = F(n-1) + F(n-2),F(1) = 1,F(2) = 1。
Fibonacci数列可以用很直观的二叉递归程序来写,用C++语言的描述如下:
long fib1(int n) { if (n <= 2) { return 1; } else { return fib1(n-1) + fib1(n-2); } }
看上去程序的递归使用很恰当,可是在用VC2005的环境下测试n=37的时候用了大约3s,而n=45的时候基本下楼打完饭也看不到结果……显然这种递归的效率太低了。
例如,用下面一个测试函数:
long fib1(int n, int* arr) { arr[n]++; if (n <= 2) { return 1; } else { return fib1(n-1, arr) + fib1(n-2, arr); } }
这时,可以得到每个fib(i)被计算的次数:
fib(10) = 1 fib(9) = 1 fib(8) = 2 fib(7) = 3 fib(6) = 5 fib(5) = 8 fib(4) = 13 fib(3) = 21 fib(2) = 34 fib(1) = 55 fib(0) = 34
可见,计算次数呈反向的Fibonacci数列,这显然造成了大量重复计算。
我们令T(N)为函数fib(n)的运行时间,当N>=2的时候我们分析可知:T(N) = T(N-1) + T(N-2) + 2
其实,这违反了递归的一个规则:合成效益法则。
合成效益法则(Compound interest rule):在求解一个问题的同一实例的时候,切勿在不同的递归调用中做重复性的工作。 所以在上面的代码中调用fib(N-1)的时候实际上同时计算了fib(N-2)。这种小的重复计算在递归过程中就会产生巨大的运行时间。
用一叉递归程序就可以得到近似线性的效率,用C++语言的描述如下:
long fib(int n, long a, long b, int count) { if (count == n) return b; return fib(n, b, a+b, ++count); } long fib2(int n) { return fib(n, 0, 1, 1); }
这种方法虽然是递归了,但是并不直观,而且效率上相比下面的迭代循环并没有优势。
Fibonacci数列用迭代程序来写也很容易,用C++语言的描述如下:
//也可以用数组将每次计算的f(n)存储下来,用来下次计算用(空间换时间) long fib3 (int n) { long x = 0, y = 1; for (int j = 1; j这时程序的效率显然为O(N),N = 45的时候 <1s就能得到结果。
本文地址:http://www.nowamagic.net/librarys/veda/detail/601,欢迎访问原出处。