马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?我要加入
x
Fibonacci数列F(n)递归地定义为:
1 n<=2
F(n)={
F(n-1)+F(n-2) n>2
列出前几项:1,1,2,3,5,8,13,21,34。。。
注意到这些数字没有,很多都是在大自然中出现的,我知道的少,不过你可以在互联网上搜一下,关键词:黄金分割。
没错,这个数列中体现了黄金分割,用数学方法很容易证明。首先它是发散的,但是不妨假设F(n+1)/F(n)是可以收敛的,设e=limF(n+1)/F(n),由递推方程:F(n)=F(n-1)+F(n-2),两边同除F(n-1)得(在极限情况下):e=1+1/e,解出来就得e=1.618...,同时也得知它近似地相当于指数数列1.618^n,至少会以这样的增涨率增涨。
以下总结一下Fibonacci数列的计算方法。
1,直接递归计算。
int fibonacci(int n)
{
if(n<=2)
return 1;
return fibonacci(n-1)+fibonacci(n-2);
}
它的计算效率同它的数值增涨效率一样是指数型的(O(1.618^n)),因为它会在递归中重复计算子问题,改进的方法就是‘打表’,把已经计算过的F(n)记录下来,在以后的计算中只管用就是了,也叫备忘录方法,也是DP算法的一个组成部分。
2、备忘录方法。
int fibonacci(int n)
{
if(mem(n)>0)
return mem(n);
return mem(n)=fibonacci(n-1)+fibonacci(n-1);
}
也可以直接用递推法,先开一个表f(n),然后由f(1)=f(2)=1开始计算。
inf fibonacci(int n)
{
if(n<=2)
return 1;
int *f=new int[n+1];
f[1]=f[2]=1;
for(int i=3;i<=n;++i)
f=f[i-1]+f[i-2];
int result=f[n];
delete[] f;
return result;
}
前者是自顶向下,后者是自底向上,其效率是一样的,都是O(n)。从指数型复杂度到线性复杂度,是多大的提高啊。然而效率还可以提高。
3、矩阵的方法。
思想来源上上次PKU的acm warmup
http://acm.pku.edu.cn/JudgeOnline/problem?id=3070
{{F(n+1),F(n)},
{F(n),F(n-1)}}
=
{{1,1} ^n
{1,0}}
我当时就想,用加法算都只能是O(n)的,换成n个矩阵的连乘不是更废劲吗?其实不然,乘法方法有比加法更好的性质,用加法只能利用前两个的值,而乘法却不同,因为乘法有结合律,可以大幅度下降算法的耗时。
令A(n)表示一个矩阵序列
A(n)=
{{F(n),F(n-1)},
{F(n-1),F(n-2)}
那么A(2)={{1,1},{1,0}},由那个表达式得到:
A(n)=A(2)^(n-1),A(2)是己知的2*2矩阵,现在的问题就是如何求
A(2)^n
因为方阵的乘法有结合律,所以
A(2)^n=A(2)^(n/2)*A(2)^(n/2),不妨设n是偶数
所以求A(n)就可以化成求A(n/2)并作一次乘法,所以递归方程是:
T(n)=T(n/2)+O(1)
它的解是O(lbn),不可思议吧。
这是我AC的代码:- #include <iostream>
- using namespace std;
- struct Matrix22
- {
- int a,b,c;
- void operator*=(const Matrix22 &m);
- void display();
- };
- void Matrix22::operator *=(const Matrix22 &m)
- {
- int p=b*m.b;
- int aa=a*m.a+p;
- int bb=a*m.b+b*m.c;
- int cc=p+c*m.c;
- a=aa%10000;
- b=bb%10000;
- c=cc%10000;
- }
- void Matrix22::display()
- {
- printf("{%d,%d,%d},\n",a,b,c);
- }
- int main(void)
- {
- Matrix22 base[31]={
- {1,1,0},{2,1,1},{5,3,2},
- {34,21,13},{1597,987,610},{4578,8309,6269},
- {7565,7723,9842},{3954,4261,9693},{237,9867,370},
- {3858,9269,4589},{8525,5243,3282},{4674,4101,573},
- {4477,7947,6530},{8338,2629,5709},{3885,9563,4322},
- {4194,3541,653},{8317,3227,5090},{6018,4389,1629},
- {9645,2683,6962},{4514,6581,7933},{5757,3707,2050},
- {4898,549,4349},{1805,6603,5202},{7634,7221,413},
- {797,7387,3410},{2978,7109,5869},{6365,3323,3042},
- {5554,9461,6093},{7437,2267,5170},{8258,69,8189},
- {9325,4843,4482}
- };
- int n;
- while(1)
- {
- scanf("%d",&n);
- if(n==-1)
- break;
- if(n<2)
- printf("%d\n",n);
- else
- {
- Matrix22 x={1,0,1};
- --n;
- for(int i=0;n;++i,n>>=1)
- {
- if(n & 0x1)
- x*=base[i];
- }
- printf("%d\n",x.a);
- }
- }
- return 0;
- }
复制代码 转自算法驿站:http://blog.programfan.com/
[ 本帖最后由 风花雪月 于 2007-4-28 06:39 编辑 ] |