欧拉计划002:偶斐波那契数

来源:互联网 发布:displaycal mac 编辑:程序博客网 时间:2024/06/02 23:50

题目:

斐波那契数列中的每一项都是前两项的和。由1和2开始生成的斐波那契数列前10项为:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …

考虑该斐波那契数列中不超过四百万的项,求其中为偶数的项之和。

通过观察,可以看出该数列的具有这样的结构:奇,偶,奇,奇,偶.... 偶数项间隔两个奇数项出现.所以这题实际是要求斐波那契数列的通项(或者某些通项)

为了统一,在此重新定义一下斐波那契数列,与题目中的定义稍稍有些不同,增加了两个项.

F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2).

由定义得出的,递归的求法如下:

int fibonacci(int n){if (n == 0)return 0;else if (n == 1)return 1;elsereturn fibonacci(n - 1) + fibonacci(n - 2);}
这个方法直接说明了定义,很好想,但是效率很低,时间复杂度是指数级的.因为很多项是被重复计算多次的.例如算F(4)的时候,F(2)就被重复算了2次.

为了避免这种重复计算,可以创建一个数组来保存已经计算的结果,使得时间复杂度为线性.

#include <stdlib.h>long long fibonacci (int n){    long long *tmp = (long long *) malloc (sizeof (long long) * (n + 1));    tmp [0] = 0;    if (n)    {        tmp [1] = 1;        for (int i = 2; i <= n; ++i)            tmp [i] = tmp [i - 1] + tmp [i - 2];    }    free(tmp);    return tmp [n];}

由于本题只要求算偶数项的和,而偶数项又是间隔两项出现一次的,所以可以只求这些项,而把其他项当成中间项.只要求和,也不必声明数组存储中间结果.代码如下:
#include <stdio.h>int main(){const int MAX = 4000000;int f0 = 0, f1 = 1, f2;int sum = 0;while (f0 < MAX){sum += f0;f2 = f0 + f1;f0 = f2 + f1;f1 = f0 + f2;}printf("斐波那契数列中数值不超过%d的项,这些项中值为偶数的项之和%d\n", MAX, sum);return 0;}

也可以用递归的方法来求解这些项.只需求出F(n)与F(n-3),F(n-6)的递归式即可.推导如下:

n≥6时,

F(n)=F(n-1)+F(n-2)=(F(n-2)+F(n-3))+F(n-2)=2F(n-2)+F(n-3)=2(F(n-3)+F(n-4))+F(n-3)=3F(n-3)+2F(n-4)

由定义有 F(n-4)=F(n-5)+F(n-6)(①

F(n-3)=F(n-4)+F(n-5)②

①-②得2F(n-4)=F(n-3)+F(n-6)

回代得F(n)=4F(n-3)+F(n-6)

观察数列看出,F(3n)都是偶数.

把3n代入上式,得F(3n)=4F(3(n-1))+F(3(n-2)).

所以可以定义新数列f(n),表示F(n)中偶数项,递归定义如下:

f(0)=0,f(1)=2,f(n)=4f(n-1)+f(n-2).

很容易写出以下的代码:

int even_fibonacci(int n){if (n == 0)return 0;else if (n == 1)return 2;elsereturn 4 * even_fibonacci(n - 1) + even_fibonacci(n - 2);}

尽管它效率依然很低:-)

0 0
原创粉丝点击