1.《趣味算法》原文章节内容-神奇的兔子数列
👍原文章节:
如果说数学是皇冠上的一颗明珠,那么算法就是这颗明珠上的光芒,算法让这颗明珠更加熠熠生辉,为科技
进步和社会发展照亮了前进的路。数学是美学,算法是艺术。 走进算法的人,才能体会它的无穷魅力。
多年来,我有一个梦想,希望每-位提到算法的人,不再立即紧皱眉头,脑海里闪现枯燥的公式、冗长的代
码;我希望每一位阅读和使用算法的人,体会到算法之美,就像躺在法国普罗旺斯小镇的长椅上,呷一口红
酒,闭上眼睛,体会舌尖上的美味,感受鼻腔中满溢的薰衣草的芳香…
🤎以上这一段内容写的很棒
很多人提到算法会感觉很深奥,算法本身就具有一定的复杂性。也许算法这个名词听上去很抽象,让人联想不到任何具体的物体。也许你会觉得算法与自己的生活并无太多关系,它只不过存在于那些闲得无聊的数学家或计算机专业人士的脑海中.,但这本《趣味算法》很有趣书哈中所有的示例都与生活息息相关,淋漓尽致地展现了算法解决问题的本质,让你爱上算法,乐在其中。
👍原文例子:
假设第1个月有1对初生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子, 兔子永不死去.... .那么,由1对初生的兔子开始, 12个月后会有多少对兔子呢? 兔子数列即斐波那契数列,它的发明者是意大利数学家莱奥纳尔多斐波那契( Leonardo Fibonacci , 1170-1250)。 1202年 ,莱奥纳尔多撰写了 《算盘全书》( Liber Abaci) ,该书是一 部较全面的初等数学著作。 书中系统地介绍了印度- 阿拉伯数码及其演算法则,以及中国的“盈不足术”;此外还引入了负数,并研究了些简单的一次同余式组。
原文解析:
不妨拿新出生的1对小兔子分析。
第1个月,小兔子①没有繁殖能力,所以还是1对。
第2个月,小兔子①进入成熟期,仍然是1对。
第3个月, 兔子①生了1对小兔子②,于是这个月共有2 ( 1+1=2 )对兔子。
第5个月,兔子①又生了1对小兔子④,而在第3个月出生的兔子②也生下了1对小兔子⑤,因此共有5 ( 2+3=5 )对兔子。
第6个月,兔子①②③各生下了对小兔子 ,新生的3对兔子加上原有的5对兔子,这个月共有8( 3+5=8 )对兔子。
…
为了让表达更清楚,可图示分别表示新生兔子、成熟期兔子和生育期兔子,兔子的繁殖过程如图1-9所示。
这个数列有如下十分明显的特点:从第3个月开始,当月的兔子数=.上月兔子数+当月新生兔子数,而当月新生兔子数正好等于上上月的兔子数。因此,前面相邻两项之和便构成后一项,换言之:
当月的兔子数=上月兔子数+上上月的兔子数
2.算法设计
首先按照递归表达式设计一个递归算法,见算法1-8。
//算法1-8 int Fib1(int n){ if(n==1||n==2) return 1; return Fib1(n-1)+Fib1(n-2); }
算法1-8的时间复杂度属于爆炸增量函数,这在算法设计中是应当避开的,那么算法1-8能不能改进呢;
斐波那契数列中的每一项(开头的两项除外)是前两项之和,如果记录前两项的值,则只需要一次加法运算就可以得到当前项的值,时间复杂度会不会更低一些呢?不妨用数组试试看,见算法1-9。
//算法1-9 int Fib2(int n){ int *F=new int[n+1];//定义一个长度为n+1的数组,空间尚未使用 F[1]=1; F[2]=1; for(int i=3;i<=n;i++) F[i]=F[i-1]+F[i-2]; return F[n]; }
很明显,算法1-9的时间复杂度为O(n)。因为算法1-9仍然遵从F(n)的定义,所以正确性没有问题,但时间复杂度却从算法1-8的指数阶降到了多项式阶,算法效率有了重大突破!
算法1-9使用了一个辅助数组记录中间结果,空间复杂度也为O(n)。其实我们只需要得到第n个斐波那契数,中间结果只是为了下一次使用,根本不需要记录。因此,我们可以采用迭代法进行算法设计,见算法1-10。
//算法1-10 int Fib3(int n){ if(n=1||==2) return 1; int S1=1;//用51和52记录前面的两项 int s2=1; for(int 13:;<-0:i++){ int tmp=s1+s2; s1=s2; s2=tmp; } return s2; }
算法1-10使用了几个辅助变量进行迭代,时间复杂度为O(n) ,但空间复杂度降到了0(1)。
2.算法设计-动态规划思想
算法中的分治思想。该思想的核心是将复杂的问题分解为小的、简单的问题,解决这些小问题,然后将小问题的解答合并成为原来大问题的解。
施行分治策略是基于以下几点认识:
- 小问题比大问题更容易解决。
- 将小问题解答组装成大问题解答所需要的成本低于直接解决大问题的成本。
- 小问题又可以按照同样方法分解为更小的问题。
分治策略在很多问题上给我们带来了高效的解决方案。但我们所讲到的分治策略是比较简单的、直接的,并没有对子问题的属性进行分析,从而丧失了对某些子问题属性加以利用的机会.
2009年12月26日,耗时4年半、耗资近1200亿元的武广客运专线开通营运。该线路沿着原来的京广铁路 武汉一广州段途经的城市行走,并沿途新建所有车站。 这样,沿途的每个城市就有两个车站: 一个为原来的京广铁路车站;一个为武广客运专线的新车站。每个城市的两个车站间都有公交系统相连接。 两条线路都有列车行走。这样,乘客从武汉到广州就可以选择两条线路中的任意一条, 并且在任何中间站可以选择换到另一条铁路上,如图所示。
显然,走新的武广客运专线将比走原京广线更快。但正是由于速度快,窗外的风景将一闪而过,难以欣赏。而走原京广线速度慢,但可以欣赏窗外的风景。如果欣赏风景那令人愉悦的感觉可以与时间进行相抵,那么走原京广线反而会比走武广客运专线快。例如,从长沙到衡阳走客运专线所花时间为50分钟,而走原京广线花费时间为90分钟,但由于沿途美景而抵掉45分钟时间(例如在衡阳车站北面30公里处铁轨两侧,可以欣赏到推马救列车的欧阳海同志纪念碑和伟大领袖毛主席的“为人民利益而死,就比泰山还重”的苍劲题词),因此走原京广线反而在心理时间上只有45分钟,即比走武广客运专线更快。
如果每对相邻城市间走高速铁路和走普速铁路的时间都已知,并且走普速铁路的心理时间抵掉值也已知,那么乘客要做的决策就是如何选择行走线路而获得最佳的心理时间成本。具体来说,就是乘客在每个中间站点都可以做出如下两种选择之—:(a)继续当前线路前往下一站: (b)乘坐公交到同城的另一个车站,从另一条线路继续前行。不同的选择将导致不同的心理时间成本,而一个城市两个车站之间的公交交通时间也有不同。乘客应该如何选择是好呢?也就是乘客在到达每个车站后都要考虑是否需要改乘另一条线路,从而以最短心理时间达到终点。
我们用什么样的办法来给乘客进行规划呢?
一种很直接的解答是尝试所有的可能,然后选择时间最短的方案。显然,这种方式的时间复杂性很高:在每个城市有2种选择,这样一共有2 6 2^626种可能。我们需要计算这26种可能线路的每一条线路所需的时间。计算2 6 2^626种可能也许计算机还能胜任,但如果这个n很大呢?
当n很大时,2 n 2^n2n的渐近增长趋势非常快!
回想【神奇的兔子数列】计算斐波那契数时,标准的分治策略是按照其递归定义进行求解,将更大的一项分解为小的两项, 这样一直递归到 T0 和T1但这种分治的效率并不高,由于需要多次;重复计算同样的项,所以其渐近趋势为指数级。但如果采用由底至上的策略,从T0和T1开始,按照T0、T1、T2、… Tn的顺序-一个个计算,这样就可以避免重复,获得线性级效率!而这种由底至上构建大问题解答的方案就是所要论述的动态规划策略!