算法六:递推(编程老师肯定没告诉过你简单的斐波那契数列也可以和黄金分割比联系起来)

递推算法是一种很常用的算法思想,在数学计算等场合有着广泛的应用。该算法适用于有明确公式的情况,通过已知条件,利用特定关系得出中间推论,逐步递推,直至得到结果为止。

不断利用已有的信息推导出新的东西。利用现有信息得到新信息,是递推算法的核心。

递推算法可分为顺推法和逆推法两种

  • 1、顺推法
    从已知条件出发,逐步推算出要解决问题的方法。例如,斐波那契数列就可以通过顺推法不断递推算出新的数据。
  • 2、逆推法
    从已知的结果出发,用迭代表达式逐步推算出问题开始的条件,即顺推法的逆过程。

例题一、顺推实例:斐波那契数列

13世纪初,欧洲数学家斐波那契在他的著作《算盘书》中出了一个有趣的题目:如果1对兔子每月能生1对小兔子,而每对小兔在它出生后的第3个月里,又能开始生1对小兔子,假定在不发生死亡的情况下,由1对初生的兔子开始,1年后能繁殖出多少对兔子?

解题思路:

(1)首先将兔子分为三种:大兔(已能生育小兔)、1个月大的小兔(当月出生的小兔)、2个月大的小兔(上月出生的小兔,还不能生育小兔),到第3个月时,2个月大的小兔就成大兔了。
(2)初始状态时,只有1对初生的小兔(1个月大的小兔),所以总数为1对。
(3)第1个月时,1个月大的小兔成长为2个月大的小兔,还是没有繁殖能力,所以总数仍然是1对。
(4)第2个月时,2个月大的小兔成长为大兔,将繁殖1对1个月大的小兔,因此总数将是2对。
(5)第3个月时,仍然只有1对大兔,将繁殖1对1个月大的小兔,同时上月的1对1个月大的小兔将成长为2个月大的小兔,因此总数将为3对。
(6)以此类推,得出规律,当前项数据(从第3个数开始)为前面相邻两项之和
在这里插入图片描述

特点:斐波那契数列有许多奇特的性质,例如,从第3个数起,相邻两个数的比值是随序号的增加而逐渐趋于黄金分割比的,即Fn-1/Fn→0.618…。由于斐波那契数都是整数,两个整数相除之商是有理数,所以只是逐渐逼近黄金分割比这个无理数。

从表的最后一列数据可以看出,斐波那契数列可使用递推算法来得到,由上两个月的兔子数量相加得到本月的兔子总数(对)
具体算法如下:
(1)设初始值为F0=1,第1个月兔子总数F1=1;
(2)第2个月兔子总数F2=F0+F1;
(3)第3个月兔子总数F3=F1+F2;
(4)第n个月兔子总数Fn=Fn-2+Fn-1。

详细C代码如下:

#include<stdio.h>
#define num 13

int main(){
	int i;
	long fib[num] = {1, 1};
	for(i = 2; i < num; i++){
		fib[i] = fib[i - 1] + fib[i - 2];
	}
	for(i = 0; i < num; i++){
		printf("%d月兔子总数为%lld对\n", i, fib[i]);
	}
	return 0;
} 

在这里插入图片描述

例题二、逆推实例:该存多少钱

父亲准备为小龙的4年大学生活一次性在银行储蓄一笔钱,使用整存零取的方式,控制小龙每月的月底只能提取1000元准备下月使用。假设银行一年整存零取的年利息为1.71%,请编程计算出父亲至少需要一次性存入多少钱才够小龙4年大学生活(4年的利息也应计算在内)

【解题思路】分析存钱和取钱的过程,可以采用逆推的方法。因为是按月取钱,因此需要将4年分为48个月,每个月分别进行计算。若在第48月小龙大学毕业时连本带息要取1000元,则要先求出第47个月时银行存款的具体数额:第47月月末存款=1000/(1+0.0171/12)(前面给出的是年利率,为简化程序,按年利率除以12得到月利率)

第46月月末存款=(第47月月末存款+1000)/(1+0.0171/12);
以此类推,可以求出第45月、第44月…月末存款的数值:
第45月月末存款=(第46月月末存款+1000)/(1+0.0171/12);
第44月月末存款=(第45月月末存款+1000)/(1+0.0171/12);
……
第2月月末存款=(第3月月末存款+1000)/(1+0.0171/12);
第1月月末存款=(第2月月末存款+1000)/(1+0.0171/12);
通过以上推理过程就可以很容易地求出最初要存入多少钱。

在这里插入图片描述
详细C代码如下:

#include<stdio.h>

int main(){
	double fetch = 1000;
	double rate = 0.0171;
	double deposit[49];
	deposit[48] = 1000;
	int i;
	for(i = 47; i > 0; i--){
		deposit[i] = (deposit[i + 1] + 1000) / (1 + 0.0171 / 12);
	}
	for(i = 1; i <= 48; i++){
		printf("第%d月的存款数为:%lf\n", i, deposit[i]);
	} 
	return 0;
} 

运行结果如下:
在这里插入图片描述
在这里插入图片描述
所以最初存入了46364.618566元(估计值不精确)

而有的人可能代码是这样写的:

#include<stdio.h>

int main(){
	double sum = 1000 / (1 + 0.0171 / 12);		/* 47月末的存款 */ 
	printf("%.2f\n", sum);
	int i;
	for(i = 0; i < 47; i++){
		sum = (sum + 1000) / (1 + 0.0171 / 12); 
	}
	printf("%.2f\n", sum);
	return 0;
} 

乍一看感觉也是对的,但是其实第一个变量就错了,这样的逆推题最好就是用数组形式存储,按之前那个公式,
第n - 1月月末存款 = (第n月月末存款 + 1000)/ (1 + 月利率)
即,money[i] = (money[i + 1] + 1000) / (1 + 月利率),
47月末的存款 = (48月末存款 + 1000)/(1 + 月利率),而且这个代码运行出的答案46363.29也不对

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值