本题目来源为SICP 习题1.19
先来看常规的斐波那契计算方法
int fib(int n)
{
return n<2 ? n:fib(n-1)+fib(n-2);
}
不难发现,这种计算方法做了太多的冗余计算,实际上这一过程的增长相对于n是指数的,我们可以通过建立备忘录的方式来将算法复杂度减成线性的
#include
using namespace std;
vector <int> opt; //opt在main函数中初始化大小为n
int fib(int n)
{
if( n!=0 && opt[n]==0)
opt[n]=fib(n-1)+fib(n-2);
return opt[n];
}
另一种方法,利用迭代,减少函数调用:
#include
#include
using namespace std;
vector<int> opt;
int main(void)
{
int i,n;
cin>>n
opt = vector<int>(n);
opt[1]=1;
for(i = 2;i <= n;i++)
opt[i] = opt[i-1] + opt[i-2];
cout<return 0;
}
存在着一种以对数步数求出斐波那契树的巧妙算法,我们先来看下面这种算法:
int fib(int n)
{
return fib_iter(1,0,n);
}
int fib_iter(a,b,count)
{
if(count == 0)
return b;
return fib_iter(a+b,a,count-1);
}
在这种算法中,我们每次递归都将a+b的值赋给a,把a的值赋给b,通过观察可以发现,从1和0开始将规则反复应用n次,将产生一对数fib(n)和fib(n+1),现在将这种规则看成
a = b*q + a*q + a*p
b = b*p + a*q
其中p=0,q=1
把这种变换称为T变换,那么对于T的平方来说,有:
a = (bp+aq)p+(bq+aq+ap)*q+(bq+aq+ap)*p = b(2pq+q^2)+a(p^2+2pq+3q^2)
b = (bp+aq)p+(bq+aq+ap)q = b(p^2+q^2)+a(q^2+2pq)
int fib(int n)
{
return fib_iter(1,0,0,1,n);
}
int fib_iter(int a,int b,int p,int q,int count)
{
if (count == 0)
return b;
else
if (count%2)
return fib_iter(b*p+a*q+a*p,b*p+a*q,p,q,count-1);
else
return fib_iter(a,b,p*p+q*q,q*q+2*p*q,count/2);
}