算法学习与应用从入门到精通
上QQ阅读APP看书,第一时间看更新

2.2 递推算法思想

知识点讲解:光盘:视频讲解\第2章\递推算法思想.avi

与枚举算法思想相比,递推算法能够通过已知的某个条件,利用特定的关系得出中间推论,然后逐步递推,直到得到结果为止。由此可见,递推算法要比枚举算法聪明,它不会尝试每种可能的方案。

2.2.1 递推算法基础

递推算法可以不断利用已有的信息推导出新的东西,在日常应用中有如下两种递推算法。

① 顺推法:从已知条件出发,逐步推算出要解决问题的方法。例如斐波那契数列就可以通过顺推法不断递推算出新的数据。

② 逆推法:从已知的结果出发,用迭代表达式逐步推算出问题开始的条件,即顺推法的逆过程。

2.2.2 实践演练——解决“斐波那契数列”问题

为了说明递推算法的基本用法,接下来将通过一个具体实例的实现过程,详细讲解递推算法思想在编程过程中的基本应用。

实例2-3 使用顺推法解决“斐波那契数列”问题

源码路径 光盘\daima\2\shuntui.c

问题描述:斐波那契数列因数学家列昂纳多•斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

算法分析:以新出生的一对小兔子进行如下分析。

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

② 2个月后,一对小兔子生下了一对新的小兔子,所以共有两对兔子。

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

……

依次类推可以列出关系表,如表2-1所示。

表2-1 月数与兔子对数关系表

表中数字1,1,2,3,5,8……构成了一个数列,这个数列有个十分明显的特点:前面相邻两项之和,构成了后一项。这个特点的证明:每月的大兔子数为上月的兔子数,每月的小兔子数为上月的大兔子数,某月兔子的对数等于其前面紧邻两个月的和。

由此可以得出具体算法如下所示:

设臵初始值为F0=1,第1个月兔子的总数是F1=1。

第2个月的兔子总数是F2= F0+F1

第2个月的兔子总数是F3= F1+F2

第3个月的兔子总数是F4= F2+F3

………

n个月的兔子总数是Fn= Fn-2+Fn-1。

具体实现:根据上述问题描述,根据“斐波那契数列”的顺推算法分析,编写实现文件shuntui.c,具体实现代码如下所示。

          #include <stdio.h>
          #define NUM 13
          int main()
          {
          int i;
              long fib[NUM] = {1,1}; //定义一个拥有13个元素的数组,用于保存兔子的初始数据和每月的总数
          //顺推每个月的总数
          for(i=2; i<NUM; i++)
              {
          fib[i] = fib[i-1]+fib[i-2];
              }
          //循环输出每个月的总数
          for(i=0; i<NUM; i++)
              {
                printf("第%d月兔子总数:%d\n", i, fib[i]);
              }
          getch();
          return 0;
          }

执行后的效果如图2-4所示。

图2-4 “斐波那契数列”问题执行效果

2.2.3 实践演练——解决“银行存款”问题

一个实例不能说明递推算法思想的基本用法,接下来开始使用逆推算法解决“银行存款”问题。

实例2-4 使用逆推法解决“银行存款”问题

源码路径 光盘\daima\2\nitui.c

问题描述:母亲为儿子小Sun 4年的大学生活准备了一笔存款,方式是整存零取,规定小Sun每月月底取下一个月的生活费。现在假设银行的年利息为1.71%,请编写程序,计算母亲最少需要存入多钱?

算法分析:可以采用逆推法分析存钱和取钱的过程,因为按照月为周期取钱,所以需要将4年分为48个月,并分别对每个月进行计算。

如果在第48月后Sun大学毕业时连本带息要取1000元,则要先求出第47个月时银行存款的钱数:

第47月月末存款=1000/(1+0.0171/12);

第46月月末存款=(第47月月末存款+1000)/(1+0.0171/12);

第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)。

具体实现:编写实现文件nitui.c,具体实现代码如下所示。

        #include <stdio.h>
        #define FETCH 1000
        #define RATE 0.0171
        int main()
        {
            double corpus[49];
            int i;
            corpus[48]=(double)FETCH;
            for(i=47; i>0; i--)
            {
            corpus[i]=(corpus[i+1]+FETCH)/(1+RATE/12);
            }
            for(i=48; i>0; i--)
            {
              printf("%d月月末本利共计:%.2f\n", i, corpus[i]);
            }
            getch();
            return 0;
        }

执行后的效果如图2-5所示。

图2-5 “银行存款”问题执行效果