目录
- 【算法】递推法和递归法
- 递推算法
- 递推算法的特点
- 递归算法
- 递归算法的特点
- 递归法与递推法的算法设计例题
- 例题一:斐波那契数列(递归递推两种方法 以及 改进算法)
- 例题二:数字三角形问题
- 例题三:扑克牌42点问题
更多算法例题链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题
【算法】递推法和递归法
递推算法和递归算法是两种常用的算法思想,它们在解决实际问题时常常被使用。虽然它们的名称相似,但在实现和应用上存在一些区别。
递推算法
递推法的核心在于找到递推关系式。这种方法可以将复杂的计算过程转化为简单的重复步骤,充分利用计算机在运行程序时的时间局部性和空间局部性。
递推算法的特点
递推算法解题的基本思路:
- 将复杂计算转换为简单重复运算;
- 通过找到递推关系式进行简化运算;
- 利用计算机的特性,减少运行时间。
- 递推算法的一般步骤:
根据题目确定数据项,并找到符合要求的递推关系式;
- 根据递推关系式设计递推程序;
- 根据题目找到递推的终点;
- 单次查询可以不进行存储,
- 多次查询都要进行存储;
- 按要求输出答案即可。
递归算法
递归算法:递归算法是一种自顶向下的算法,它通过不断地直接或间接调用自身的函数,通过每次改变变量完成多个过程的重复计算,直到到达边界之后,结束调用。(与递推法相似的是,递归与递推都是将一个复杂过程分解为几个简单重复步骤进行计算。)
递归算法的实现的核心是分治策略,即分而治之,将复杂过程分解为规模较小的同类问题,通过解决若干个小问题,进而解决整个复杂问题。
递归算法的特点
递归算法设计的一般步骤:
- 根据题目设计递归函数中的运算部分;
- 根据题目找到递归公式,题目可能会隐含给出,也可能需要自己进行推导;
- 找到递归出口,即递归的终止条件。
递归法与递推法的算法设计例题
例题一:斐波那契数列(递归递推两种方法 以及 改进算法)
分析得:
- 递推:
这个题给出递推式 :
F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n−1)+F(n−2) F(n)=F(n−1)+F(n−2)
转化为可用的递推关系,即
F ( n ) + F ( n + 1 ) = F ( n + 2 ) F(n)+F(n+1)=F(n+2) F(n)+F(n+1)=F(n+2)
递推代码示例:
#include <iostream>
using namespace std;
int main()
{
int n; //第几个数
int x=0; //F(n)
int y=1; //F(n+1)
int ans; //F(n+2)
cin>>n;
if(n==0) ans=0;
else if(n==1) ans=1;
else {
for(int i=2;i<=n;i++)
{//递推
ans=x+y;
x=y;
y=ans;
}
}
cout<<ans<<endl;
}
改进算法(假如:将进行M次查询,每次输入一个N,其中n小于30):
存储型的递推
//每次查询后就存储下来 方便下次的查询
#include <iostream>
using namespace std;
int F[35];
void init()
{
F[0]=0;
F[1]=1;
for(int i=2;i<=30;i++)
{
F[i]=F[i-1]+F[i-2];
}//运行的时候 前三十个 每个都计算了
}
int main()
{
int m; //m次查询
int n; //第几个数
init();
cin>>m;
while(m>0){
m-=1;
cin>>n;
cout<<F[n]<<endl;
}
}
- 递归
递归表达式为:
F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n−1)+F(n−2)
递归出口为:
//递归出口1
if(n==0)
return 0;
//递归出口2
else if(n==1 )
return 1;
递归代码示例:
#include <iostream>
using namespace std;
int fn(int n)
{
//递归出口1
if(n==0)
return 0;
//递归出口2
else if(n==1 )
return 1;
else
return fn(n-1)+fn(n-2); //递归关系式
}
int main()
{
int n; //第几个数
int ans;
cin>>n;
ans=fn(n);
cout<<ans<<endl;
}
改进递归(假如:将进行M次查询,每次输入一个N,其中n小于30)算法:
存储型的递归
#include <iostream>
using namespace std;
int F[35];
int fn(int n)
{
//递归出口1
if(n==0)
{
F[0]=0;
return 0;
}
//递归出口2
else if(n==1 )
{
F[1]=1;
return 1;
}
else
{
F[n]=fn(n-1)+fn(n-2);
return F[n]; //递归关系式
}
}
int main()
{
int m; //m次查询
int n; //第几个数
fn(30);//一次性 全算了一遍
cin>>m;
while(m>0){//然后 直接输出结果
m-=1;
cin>>n;
cout<<F[n]<<endl;
}
}
例题二:数字三角形问题
输入样例:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例:
30
分析题目可得递推表达式为:
a[i][j] = max{a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1]}
题解代码示例:
#include<iostream>
using namespace std;
int main()
{
int n; //n层
int a[101][101]; //路径矩阵
cin>>n;
//输入数字三角形的值
for (int i=1; i<=n; i++)
{
for (int j=1; j<=i; j++)
{
cin>>a[i][j]; //输入原始数据
}
}
//递推开始
for (int i=n-1; i>=1; i--)//从最后一层逆推
{
for (int j=1; j<=i; j++)
{
if (a[i+1][j]>=a[i+1][j+1])
a[i][j]+=a[i+1][j]; //路径选择
else
a[i][j]+=a[i+1][j+1];
}
}
cout<<a[1][1]<<endl;
}
例题三:扑克牌42点问题
输入示例:
K A Q 6 2 3
YES
第一步:对输入的数据进行处理
//对输入的数据 进行处理
for(int i=0;i<6;i++){
char c;
//scanf("%c",&c);
cin>>c;
if(c=='A')
a[i]=1;
else if(c=='J')
a[i]=11;
else if(c=='Q')
a[i]=12;
else if(c=='K')
a[i]=13;
else
a[i]=(int)(c-'0');
}
第二步:计算每种可能的结果
ans[0].push_back(a[0]);
for(int i=1;i<=5;i++){
for(int j=0;j<ans[i-1].size();j++){
ans[i].push_back(ans[i-1][j]+a[i]);
ans[i].push_back(ans[i-1][j]-a[i]);
ans[i].push_back(ans[i-1][j]*a[i]);
ans[i].push_back(ans[i-1][j]/a[i]);
}
}
第三步:判断ans[5]中是否有42
int flag = 0;
for(int i=0;i<ans[5].size();i++){
if(ans[5][i]==42){
flag=1;
break;
}
}
if(flag== 1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
题解代码示例:
#include<iostream>
#include<vector>
using namespace std;
vector<int> ans[6]; //创建大一点 记录五次计算的结果
int a[6]={0}; //存放输入的六个数据
int main()
{
for(int i=0;i<6;i++){
char c;
//scanf("%c",&c);
cin>>c;
// 根据输入字符的不同,赋予对应的值给a数组
if(c=='A')
a[i]=1;
else if(c=='J')
a[i]=11;
else if(c=='Q')
a[i]=12;
else if(c=='K')
a[i]=13;
else
a[i]=(int)(c-'0');
}
ans[0].push_back(a[0]);
// 计算可能的运算结果
for(int i=1;i<=5;i++){
for(int j=0;j<ans[i-1].size();j++){
// 将上一步结果与a[i]进行加减乘除运算,并将结果添加到ans[i]中
ans[i].push_back(ans[i-1][j]+a[i]);
ans[i].push_back(ans[i-1][j]-a[i]);
ans[i].push_back(ans[i-1][j]*a[i]);
ans[i].push_back(ans[i-1][j]/a[i]);
}
}
// 检查是否有结果等于42
int flag = 0;
for(int i=0;i<ans[5].size();i++){
if(ans[5][i]==42){
flag=1;
break;
}
}
if(flag== 1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
感谢阅读!!!
更多算法例题链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题