目录
一:前言
现在开始,作者要写一些提高编程水平的博客了,希望大家可以从中获取一些知识。喜欢的朋友也可以点个关注啦~
二:递推
递推是一种算法,它是由一个数组来进行的:首先给数组的一些特殊位置赋上初值,之后的每一个值都可以由之前的值得到,这就叫递推。
例题一:永生的兔子
题目
题目介绍:
修罗王在恐怖的冥界中找到了传说的不死秘术。为了安全起见,他对一对刚出生的小兔子施展了此魔法。现在假设秘术使得所有的兔子都不死,而且兔子在出生2个月后,就有生殖能力。每一对有繁殖能力的兔子可以生殖一对兔子。那么n个月,繁殖了多少对兔子?(n<=50)
输入格式
一个整数,表示n个月的时候
输出格式
一个整数,表示n个月的时候一共有多少兔子
输入样例 复制
3
输出样例 复制
2
思路
我们先定义一个a数组,表示第i个月共有a[i]只兔子,那么a[1]和a[2]都应该等于1。后边的公式怎么推到呢?我们先来画个图。
如图可知,第i个月的兔子数量就是大兔子数量+小兔子数量,这个月的大兔子数量就是上个月的总兔子数量(因为上个月的小兔子已经成年了,变成大兔子了。所以也就是上个月的兔子遗留下来的),这个月的小兔子数量其实就是上个月的大兔子生的,所以,就是上个月的大兔子数量。我们推出了公式:这个月的兔子数量=上个月的兔子数量+上个月的大兔子数量。
做法一
用两个数组分别存放这个月的兔子数量和这个月的大兔子数量~
上个月的大兔子数量其实就是上个月的总兔子数量
#include <bits/stdc++.h>
using namespace std;
int main(){
long long n;
cin>>n;
if(n<3){//特判
cout<<1;
return 0;
}
long long a[n+1];//总共的兔子数量
long long b[n+1];//大兔子数量
a[1]=1,a[2]=1;
b[1]=1,b[2]=1;
for(long long i=3;i<=n;i++){
b[i]=a[i-1];//保存这个月的大兔子数量
a[i]=a[i-1]+b[i-1];//累加
}
cout<<a[n];//输出结果
return 0;
}
做法二
上个月的大兔子数量其实就是上上个月的兔子数量
所以,只要一个数组来进行操作就行了。
#include <bits/stdc++.h>
using namespace std;
int main(){
long long n;
cin>>n;
if(n<3){//特判
cout<<1;
return 0;
}
long long a[n+1];//用来保存兔子数量
a[1]=1,a[2]=1;//保存初值
for(long long i=3;i<=n;i++)//循环
a[i]=a[i-1]+a[i-2];
cout<<a[n];//输出结果
return 0;
}
做法三
根据代码我们可以得知:每次我们使用的都是当前的数据和前两次的数据,如果定义一个数组有点费空间,所以,我们可以用三个变量来进行操作。这种方法叫迭代
#include <bits/stdc++.h>
using namespace std;
int main(){
long long n;
cin>>n;
if(n<3){//特判
cout<<1;
return 0;
}
long long a,b,c;//定义三个变量
a=b=1;//保存初值
for(int i=3;i<=n;i++){//循环
c=a+b;
a=b;
b=c;//迭代
}
cout<<c;//输出结果
return 0;
}
要点
1:开始时要写特判
2:给数据保存初值
3:数组或变量要用long long(因为题目说n<=50,用int会爆掉)
例题二:分平面
题目
题目描述
一条直线可以把一个平面分成2个面。2条直线,可以最多把一个平面分成4个平面,那么请问:n条直线,最多能把平面分成几个面?
输入格式
一个整数,表示一共有几条直线
输出格式
一个整数,表示可以分割成最多面的数量
输入样例 复制
3
输出样例 复制
7
思路
这道题需要转换思想,首先我们用a[i]表示第i条线可以把一张纸分成a[i]个面。
然后列一下初值
f[0]=1;
f[1]=2;
然后画个图(这是三条横线的样子)
再画一条线,我们可以发现,最多可以经过三条线,所以能增加三个平面,而且多出一条线还可以增加一条平面,所以可以增加四个平面,而这正好是第四条线。
因此,我们可以得出规律:a[i]=a[i-1]+i;(这个需要更多的推算,此处省略~)
做法一
上面我们已经得出了规律,再加上之前得出的初值,一个代码就完成了!
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int a[n+1];
if(n==0){//特判
cout<<1;
return 0;
}
a[0]=1;//赋初值
a[1]=2;
for(int i=2;i<=n;i++)
a[i]=a[i-1]+i;//运算
cout<<a[n];
return 0;
}
做法二
我们可以发现,i从2开始循环,直到n结束,每次都是加上i,而初值又是2,可以理解为1+(1+2+...+n-1+n)的和!
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int a=1;
for(int i=1;i<=n;i++)
a+=i;//运算
cout<<a;
return 0;
}
做法三
这个做法其实就是一个数学公式完成!
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
cout<<1+(n+1)*n/2;
return 0;
}
乍一看,刚开始觉得题目特别难,现在,一个公式就完成了,这种方法还是需要大家多去推敲推敲的。
要点
1:开始记得写特判(做法三不用)
2:推导过程需要大家多去回顾,多加思考
递推要点总结
第一步:先列一些初值
第二步:画图来推导公式,需要反复验证(也可以多列一些初值,根据数字找规律)
第三步:根据初值和公式实现代码
第四步:根据代码进行优化,可以优化时间,也可以优化空间。