您的位置:首页 > 其它

hdu - 1568 fibonacci

2013-08-05 20:09 369 查看
fibonacci是一个非常有趣的数列,中文翻译是“斐波那契”,我则妄称之为"肥婆纳妾",而对于肥婆纳妾我也是才刚刚接触,为什么说它有趣呢,当然不会是因为肥婆居然会纳妾啦,鄙人理由有四,

一. 有趣的兔子问题。若大家还记得中学的兔子问题,便会恍然大悟,原来自己和肥婆纳妾早已是老相识了,有道是白头如新,倾盖如故,便有这几分含味。

斐波那契在《算盘书》中提出了一个有趣的兔子问题:

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔都不死,那么一年以后可以繁殖多少对兔子?

我们不妨拿新出生的一对小兔子分析一下:

第一个月小兔子没有繁殖能力,所以还是一对;

两个月后,生下一对小兔总数共有两对;

三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对;

……

依次类推可以列出下表:





二.有趣的通项公式。这是一个用无理数来表示有理数的公式,又叫比内公式,也就是说fibonacci的通项公式叫比内公式(即肥婆纳妾的条件是比内裤~~oh my god!),这个公式将是做这道题的关键之一,公式如下:



三.这肥婆居然和黄金分割有密切关系

有趣的是:这样一个完全是自然数的数列,通项公式却是用无理数来表达的。而且当n趋向于无穷大时,后一项与前一项的比值越来越逼近黄金分割0.618.(或者说后一项与前一项的比值小数部分越来越逼近黄金分割0.618、前一项与后一项的比值越来越逼近黄金分割0.618)

1÷1=1,2÷1=2,3÷2=1.5,5÷3=1.666...,8÷5=1.6,…………,89÷55=1.6181818…,…………233÷144=1.618055…75025÷46368=1.6180339889…...

越到后面,这些比值越接近黄金比.

四.自然界的fibonacci

斐波那契数列在自然科学的其他分支,有许多应用。例如,树木的生长,由于新生的枝条,往往需要一段“休息”时间,供自身生长,而后才能萌发新枝。所以,一株树苗在一段间隔,例如一年,以后长出一条新枝;第二年新枝“休息”,老枝依旧萌发;此后,老枝与“休息”过一年的枝同时萌发,当年生的新枝则次年“休息”。这样,一株树木各个年份的枝桠数,便构成斐波那契数列。这个规律,就是生物学上著名的“鲁德维格定律”。


这些植物懂得斐波那契数列吗?应该并非如此,它们只是按照自然的规律才进化成这样。这似乎是植物排列种子的“优化方式”,它能使所有种子具有差不多的大小却又疏密得当,不至于在圆心处挤了太多的种子而在圆周处却又稀稀拉拉。叶子的生长方式也是如此,对于许多植物来说,每片叶子从中轴附近生长出来,为了在生长的过程中一直都能最佳地利用空间(要考虑到叶子是一片一片逐渐地生长出来,而不是一下子同时出现的),每片叶子和前一片叶子之间的角度应该是222.5度,这个角度称为“黄金角度”,因为它和整个圆周360度之比是黄金分割数0.618033989……的倒数,而这种生长方式就决定了斐波那契螺旋的产生。向日葵的种子排列形成的斐波那契螺旋有时能达到89,甚至144条。

回归题目,看到a
= a[n - 1] + a[n - 2],大伙肯定想着用递归,可是递归对于0
<= n <= 100000000这么大的数就显得有心无力了,从效率来说,一般的递归要进行2^100000000次调用,不算时间上的耽搁,就连栈都会溢出,所以并不可用。记忆递归的话,只需进行100000000次调用即可,效率貌似解决得了,可是fibonacci增长速度极快,在n达到100之前就溢出了(_int64比int稍后而已),而题目只要求算前四位,这又让人想起了强大的log10(n)来,不得不说,假设一个数m,m = 10^lg(m),众所周知,一个数用科学计数法表示,可以写成a+10^b而10^b只是改变a的位权,对其数值并不影响,因此我们就等于把123456789这样的数转换成1.23456789来表示(就不用担心溢出了,但不能拿来四则运算,浮点数计算有误差!!),接下来,只要用好fibonacci的公式就好了,我们来化解一下公式(我看网上的化解法)对公式取log10,取完

后如下



此时我们分析题目,注意到两点

1.位数不大于四位的全部表示出来,而大于四位的则取其前四位。
2.当n越大时,取完log后的f(n)的最后一项越来越接近0,可以忽略不计,此时再用floor函数得到lg(f(n))的小数即可(10^1 = 10,小数的话就小于10,便是科学计数法的表示)
也就是说,在n < 21时,用记忆的递归就好了,在21以后就用公式,此时后项可忽略(n = 21时,答案才超过10000)
以下是个人代码:
#include<stdio.h>
#include<cmath>
int shu[10000];
int fibonacci(int n)
{
if(shu
> 0) return shu
;
if(n == 0 || n == 1) return n;
else return shu
= fibonacci(n - 1) + fibonacci(n - 2);

}
int main()
{
int n;
shu[0] = 0;
shu[1] = 1;
while(scanf("%d",&n) == 1)
{
if(n < 21)
printf("%d\n",fibonacci(n));
else
{
double m;
m =(-0.5)*log10(5.0) + n * log10(((1.0 + sqrt(5.0))/2.0));
m = m - floor(m);
m = pow(10.0,m);
while(m < 1000) m *= 10;
printf("%d\n",(int)m);
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: