导读

信息学能够有助于孩子未来工作发展,提升孩子的综合能力。


这一节课,我们来学习递推算法,递推算法理论比较简单,但是在应用过程中,怎么得到递推公式,实现递推公式的一些细节问题还是有一定难度的,让我们走进本文看一下吧!


1 站在巨人的肩膀上

我们现在所有的工作都是基于前人的基础的,我们在前人的基础上再进行更新,再进行创造,有了我们现在科技发展的时代。


我们今天要讲的递推算法就是应用了这种思想。让我们走进本文去了解一下递推算法吧!

2 递推算法

相比于前面的搜索算法,递推算法是更偏向数学的算法,让我们一起了解一下递推算法吧!

1 什么是递推算法

首先我们来了解一下什么是递推算法


前面我们的例子讲到,我们的所有操作都是在前人的基础上继续的,我们是站在了前人的肩膀上。


递推算法就是如此,每一步的操作会与前面的一步或者多步操作存在一定的关系,通过前面的操作,可以轻松推导得到当前的操作。


这种做法有两个意义:


第一个意义是,很多情况下,我们只能得到操作与操作之间的关系,例如斐波那契数列。


第二个意义是,我们可以轻松得到操作与操作的关系,还能得到操作和其他的关系。但是我们通过前面的操作已经得到了一些结果,我们直接调用这些结果,不需要重新计算前面的操作,明显更为高效。


递推重要的是思想,重点是找到后面操作和前面操作的关系

2 等差/等比/差比数列

数列可以理解是一系列数按照某个顺序构成的线性表


在数列中,最基础的,最经典的三大数列就是:



等差数列
等比数列
差比数列


具体我们详细看一下。


1、等差数列


等差数列是说,在这一系列数中,相邻两项,后项减去前项的差是一致的。


所以对于等差数列的第i项和第i+1项,满足如下关系:


第i+1项 - 第i项 = 常数


这个常数称为公差


我们用a数组来表示数列,用a[i-1]表示第i项,用a[i]表示第i+1项。用d表示常数,那么我们有如下公式:


a[i] = a[i-1] + d


上面的式子就是等差数列的递推公式。其中,我们需要知道a[0]的值。还有他们之间的公差d。然后我们就可以利用递推公式推导出所有的项,


等差数列还有一个非常重要的是等差数列的前n项和,我们知道前n项和是前n-1项和加上数列中的第n项。


我们用数组S来表示前n项和。用S[i-1]表示前i项和,用S[i]表示前i+1项和。那么我们有如下公式:


S[i] = S[i-1] + a[i]


这个就是等差数列前n项和的递推公式。


代码实现如下:


#include<iostream>
using namespace std;
int main(){
int a[100],d,S[100],n;
cin>>n>>a[0]>>d;
S[0] = a[0];
for(int i = 1;i<n;i++){
a[i] = a[i-1]+d;
S[i] = S[i-1]+a[i];
}
cout<<a[n-1]<<endl<<S[n-1]<<endl;

return 0;
}


如果我们不需要存所有数据,我们就可以使用普通变量代替数组,节省空间:


#include<iostream>
using namespace std;
int main(){
int a,d,S,n;
cin>>n>>a>>d;
S = a;
for(int i = 1;i<n;i++){
a = a+d;
S = S+a;
}
cout<<a<<endl<<S<<endl;

return 0;
}


2、等比数列


等比数列是说,在这一系列数中,相邻两项,后项比前项的比值是一致的。


所以对于等比数列的第i项和第i+1项,满足如下关系:


第i+1项/第i项 = 常数


这个常数称为公比


我们用a数组来表示数列,用a[i-1]表示第i项,用a[i]表示第i+1项。用q表示常数,那么我们有如下公式:


a[i] = a[i-1] * q


上面的式子就是等比数列的递推公式。其中,我们需要知道a[0]的值。还有他们之间的公比q。然后我们就可以利用递推公式推导出所有的项,


等比数列还有一个非常重要的是等比数列的前n项和,我们知道前n项和是前n-1项和加上数列中的第n项。


我们用数组S来表示前n项和。用S[i-1]表示前i项和,用S[i]表示前i+1项和。那么我们有如下公式:


S[i] = S[i-1] + a[i]


这个就是等差数列前n项和的递推公式。


我们直接考虑最节省空间的写法,代码实现如下:


#include<iostream>
using namespace std;
int main(){
int a,q,S,n;
cin>>n>>a>>q;
S = a;
for(int i = 1;i<n;i++){
a = a*q;
S = S+a;
}
cout<<a<<endl<<S<<endl;

return 0;
}


3、差比数列


差比数列是等差数列和等比数列的结合,全称是等差乘等比数列。差比数列的某一项可以用下面的公式表示:


c[i] = a[i] * b[i]


其中,a和b也是两个数列,并且其中一个为等差数列,另一个为等比数列。我们一般默认a是等差数列,b是等比数列。


所以对于差比数列的相邻两项,满足如下关系:


c[i] = a[i] * b[i]
= (a[i-1]+d)*(b[i-1]*q)
= a[i-1]*b[i-1]*q + d*b[i-1]*q
= q*c[i-1] + d*b[i]


差比数列的前n项和,也是前n-1项和加上数列中的第n项。重点是差比数列前n项和的通项公式。在这里和递推没有关系,我们不讲。有兴趣以后我会给大家录视频讲解。


我们直接考虑最节省空间的写法,代码实现如下:


#include<iostream>
using namespace std;
int main(){
int a,b,c,d,q,n;
cin>>n;
cin>>a>>d; //等差数列首项和公差
cin>>b>>q; //等比数列首项和公比
c = a*b;
for(int i = 1;i<n;i++){
b = b*q;
c = q*c+d*b;
}
cout<<c<<endl;

return 0;
}


3 斐波那契数列

斐波那契数列是非常经典的递推算法应用,斐波那契数列会指定前两个数据后面的数据是其前两个数据的和。


使用数组的方式非常简单,我们如果考虑到空间复杂度,就不能使用数组,代码如下:



#include<iostream>
using namespace std;
int main(){
int a,b,c,n;
cin>>n>>a>>b;
for(int i = 3;i<=n;i++){
c = a+b;
a = b;
b = c;
}
cout<<c<<endl;

return 0;
}


4 杨辉三角

杨辉三角非常经典:


信息学赛培 | 10 站在巨人的肩膀上,开创未来——递推算法_c++


现在我们尝试使用递推算法输出杨辉三角第i行的第j个数据。


我们知道用二维数组a存储,用a[1][1]表示第一行第一列的数据。那么第i行第j列的数据满足:


如果j=1或者j=i,那么a[i][j] = 1;
否则,a[i][j] = a[i-1][j-1] + a[i-1][j];


代码如下:


#include<iostream>
#include<string.h>
using namespace std;
int a[100][100];
int main(){
int m,n;
cin>>m>>n;
if(m==n||n==1) cout<<1;
else {
for(int i = 1;i<=m;i++){
a[i][1] = 1;
a[i][i] = 1;
for(int j = 2;j<i;j++){
a[i][j] = a[i-1][j-1]+a[i-1][j];
}
}

for(int i = 1;i<=m;i++){
for(int j = 1;j<=i;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
cout<<a[m][n]<<endl;

return 0;
}


执行结果如下:


信息学赛培 | 10 站在巨人的肩膀上,开创未来——递推算法_等差数列_02


5 递推算法的难点

递推算法大家应该发现了,代码本身并不难,难点在于,如何确定其关系,并能把关系转化为合适的代码。

3 作业

本节课的作业,就是复习上面的所有知识,并完成下面的题目!

1 【NOIP1998 C】车站

火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上、下车,但上、下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为a人。从第3站起(包括第3站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第n-1站),都满足此规律。现给出的条件是:共有N个车站,始发站上车的人数为a,最后一站下车的人数是m(全部下车)。试问x站开出时车上的人数是多少?


【输入描述】
a( ≤ 20), n( ≤ 20), m( ≤ 2000),和 x( ≤ 20)


【输出描述】
从x站开出时车上的人数


【输入示例】
5 7 32 4


【输出示例】
13


参考分析表格


我们可以根据题目构建如下的表格,然后寻找其中的规律,并完成代码。


信息学赛培 | 10 站在巨人的肩膀上,开创未来——递推算法_c++_03



AI与区块链技术

信息学赛培 | 10 站在巨人的肩膀上,开创未来——递推算法_c++_04