PE2 Even Fibonacci numbers(最大菲波那列偶数)
本系列前言:PE(Project Eluer)是学Mathematica(以后我简称Mma)接触到的,不用提交代码,只用提交答案的答题网站。PE的题目会给出C++和Mma代码实现,以此学习Mma(已经被它的简洁给折服了..)。
题目
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
https://projecteuler.net/problem=2
分析
题目求由不小于四百万的偶数之和。
Fibonacii算法复习
这里涉及到求Fibonacii数列的算法,一般来说有如下几种:
n 二分递归法:用递推公式,Fn = F(n-1)+F(n-2); O(2n)
n 线性递归法:用态规划思想,保存解。Time:O(n) Place:O(n)
n 迭代:O(n),由于迭代法完胜递归法,前两种方法平时基本不用去使用;
n 其他方法(二分矩阵、公式法…)
Code部分贴上前三种方法,作为复习Fibonacii算法(我只会这三种)。
偶数求和分析:
1. 暴力法:循环到大于4000000结束,依次算出每个数的Fn,偶数则加和。O(n)
int FibEvenSum1(intlimit){
int sum = 0;
int a = 0;
int b = 1;
while (a<limit)
{
int c = b;
b += a;
a = c;
if (a % 2 == 0) sum += a;
cout << "sum:" << sum << endl;
}
return sum;
}
2. 用Mma列举出几个Fib看看(Mma实在太适合干这个了。。。)
I: Fibonacci@Range[1, 20]
O: {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765}
得到规律:其中偶数的序列为:F3,F6,F9…….所以可以从这里入口优化。
int FibEvenSum2(intlimit){
int sum = 0;
int a = 1;
int b = 1;
int c = a + b;
while (c<limit)
{
sum += c;
a = b + c;
b = c + a;
c = a + b;
cout << "sum:" << sum << endl;
}
return sum;
}
效率提高2倍,还有更beautify的….
3. 再次用Mma观察
I : Fibonacci@Range[1, 20] // Select@EvenQ
O: {2, 8, 34, 144, 610, 2584}
设新数列为En,En = 4*E(n-1)+E(n-2)
如何来的呢?Fn = F(n-1)+F(n-2)
= 2F(n-2)+F(n-3)
= 4F(n-3) + F(n - 6)
用这个递推公式优化后,效率在2的基础上提高3倍
int FibEvenSum3(intlimit){
int a = 0;
int b = 2;
int c = 0;
int sum = 0;
while (c < limit){
a = 4 * c + b;
b = 4 * a + c;
c = 4 * b + a;
if (c < limit)sum += c;
if (b < limit)sum += b;
if (a < limit)sum += a;
cout << "sum:" <<sum <<endl;
}
return sum;
}
Code
#include <iostream> using namespace std; int FibEvenSum1(int limit); int FibEvenSum2(int limit); int FibEvenSum3(int limit); int main(){ int d = FibEvenSum1(4000000); cout << endl; int f = FibEvenSum2(4000000); cout << endl; int r = FibEvenSum3(4000000); return 0; } int FibEvenSum1(int limit){ int sum = 0; int a = 0; int b = 1; while (a<limit) { int c = b; b += a; a = c; if (a % 2 == 0) sum += a; cout << "sum:" << sum << endl; } return sum; } /*1 1 2 3 5 8 13 21 34 每三个数出现一个偶数*/ int FibEvenSum2(int limit){ int sum = 0; int a = 1; int b = 1; int c = a + b; while (c<limit) { sum += c; a = b + c; b = c + a; c = a + b; cout << "sum:" << sum << endl; } return sum; } int FibEvenSum3(int limit){ int a = 0; int b = 2; int c = 0; int sum = 0; while (c < limit){ a = 4 * c + b; b = 4 * a + c; c = 4 * b + a; if (c < limit)sum += c; if (b < limit)sum += b; if (a < limit)sum += a; cout << "sum:" <<sum <<endl; } return sum; }
#include <iostream> using namespace std; __int64 fib(int i); __int64 fib2(int n, __int64 & prev); __int64 fib3(int n); long main(){ cout << fib(10); cout << fib3(10); return 0; } __int64 fib(int n){ return (2>n) ? (__int64)n:fib(n - 1) + fib(n - 2); } __int64 fib2(long n, __int64 & prev){//第n项、prev:n-1项的值 if (0 == n){//直接取值:fib(-1) = 1;fib(0) = 0; prev = 1; return 0; } else{ __int64 prevPrev; prev = fib2(n - 1, prevPrev); return prevPrev + prev; } } __int64 fib3(int n){ __int64 f = 0, g = 1;//初始化:fib(0) = 0,fib(1) = 1; while (0<n--) { g += f; f = g - f; } return f; }
Mathematica
Fibonacci@Range[1, 33] // Select@EvenQ // Total
简单粗暴!
参考: 1.邓俊辉.数据结构(C++语言版).第三版.清华大学出版社.第一章
2.hk