递推是计算机用于数值计算的一种非常重要的方法,在数学的各个领域也有广泛的应用,下面会介绍递推。
目录
1.关于递推算法
1.1 定义
递推是按照一定的规律来计算序列中的每个项,通常是通过计算前面的一些项来得出序列中的指定项的值。其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。递推法分为“顺推”和“倒推”两类模型:顺推是从问题的边界条件(初始状态)出发,通过递推关系式依次从前往后递推出问题的解。倒推是在不知道问题的边界条件(初始状态)下,从问题的最终解(目标状态或某个中间状态)出发,反过来推导问题的初始状态。
1.2 重点
1、建立正确的递推关系式;
2、分析递推关系式的性质;
3、根据递推关系式编程求解。
递推法分为“顺推”和“倒推”两类模型:
1、顺推,就是从问题的边界条件(初始状态)出发,通过递推关系式依次从前往后递推出问题的解;
2、倒推,就是在不知道问题的边界条件(初始状态)下,从问题的最终解(目标状态或某个中间状态)出发,反过来推导问题的初始状态。
2.典型的递推关系
2.1 斐波那契数列
斐波那契数列由数学家莱昂纳多·斐波那契以兔子繁殖为例子而引入,指的是这样一个数列:1、1、2、3、5、8、13、21、34、······
【题目描述】
给出一个正整数k,要求菲波那契数列中第k个数是多少。
【输入】
输入一行,包含一个正整数k。(1 ≤ k ≤ 46)
【输出】
输出一行,包含一个正整数,表示菲波那契数列中第k个数的大小。
【输入样例】
19
【输出样例】
4181
#include<bits/stdc++.h>
using namespace std;
int f[200000];
int main(){
int k;
cin>>k;
f[1] = f[2] = 1;
for (int i = 3;i <= k;i++){
f[i]=f[i-1]+f[i-2];
}
cout<<f[k]<<endl;
return 0;}
2.2 汉诺塔问题
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。上帝创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
【题目描述】
汉诺塔问题是一个经典的问题。现在A柱上有n片圆盘,要将这n片圆盘按照要求,移动到C柱上,共需移动多少次?
【输入】输入一行,包含一个正整数n。(1 ≤ n ≤ 15)
【输出】
输出一行,包含一个正整数,表示需移动的次数。
【输入样例】
6
【输出样例】
63
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int a[15],b[15],n;
cin >> n;
//只有三个柱子的情况
a[1]=1;
for(int i=2;i<=n;i++)
{
a[i]=a[i-1]*2+1;
}
memset(b,0x3f,sizeof(b)); //用0x3f初始化:数足够大并且不会溢出
cout<<a[n]<<endl;
return 0;
}
2.3 平面分割问题
【题目描述】
同一平面内有 n(n≤500)条直线,已知其中 p(p≥2)条直线相交于同一点,则这 n 条直线最多能将 平面分割成多少个不同的区域?【输入】
两个整数 n(n≤500)和 p(2≤p≤n)。【输出】
一个正整数,代表最多分割成的区域数目。
【输入样例】
12 5
【输出样例】
73
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,p,sum;
cin>>n>>p;
sum=p*2;
for(int i=p;i<n;i++)
sum+=i+1;
cout<<sum<<endl;
return 0;
}
2.4 卡特兰数
卡特兰数又称卡塔兰数,卡特兰数是组合数学中一个常出现在各种计数问题中的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名。但最早是欧拉在1753年解决凸包划分成三角形问题的时候,推出的Catalan数。
【题目描述】
宁宁考虑的是这样一个问题:一个操作数序列,1,2,…,�1,2,…,n(图示为 1 到 3 的情况),栈 A 的深度大于 �n。
现在可以进行两种操作,
- 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
- 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由
1 2 3
生成序列2 3 1
的过程。
(原始状态如上图所示)
你的程序将对给定的 n,计算并输出由操作数序列 1,2,…,n 经过操作可能得到的输出序列的总数。
【输入】
输入文件只含一个整数 n(1≤n≤18)。
【输出】
输出文件只有一行,即可能输出序列的总数目。
【输入样例】
3
【输出样例】
5
【提示】
递推
卡特兰数
【题目来源】
NOIP 2003 普及组第三题
#include<cstdio>
#define MAX_N 20
#define ll long long
using namespace std;
int n;
ll f[MAX_N];
int main()
{
f[0]=f[1]=1;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
for(int j=0;j<i;j++)
{
f[i]+=f[j]*f[i-j-1];
}
}
printf("%lld",f[n]);
return 0;
}
2.5 第二类 Stirling 数
【题目描述】
n个各不相同球放入m个相同的盒子里,球全部放完后,要求最后没有空盒!求不同的放法总数。
【输入】
一行两个数n和m
n表示球数,m表示盒子数
(0<n≤20)(0≤m≤20)
【输出】
不同且合理的放法总数
【输入样例】3 2
【输出样例】3
【提示】
递推
第二类stirling数
#include<bits/stdc++.h>
using namespace std;
long long a[25][25]; //a数组是用来递推的数组,注意本题需要使用longlong类型
int main()
{
int m,n;
scanf("%d %d",&n,&m); //输入球数以及盒子数
for(int i=1;i<=n;i++) //外层循环枚举球数
{
for(int j=1;j<=m;j++) //内层循环枚举盒子数
{
if(i<j||j==0) break;
//如果盒子数大于球数,或者球数为0,就没有方法
else if(i==1||j==1) a[i][j]=1;
//如果盒子数等于1或者球数等于1,就只有一种方法
else a[i][j]=a[i-1][j-1]+j*a[i-1][j];
//常规情况
}
}
printf("%lld\n",a[n][m]); //输出解
return 0; //结束
}
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,如果喜欢我的文章,给个关注吧!
冰焰狼 | 文
如果本篇博客有任何错误,请批评指教,不胜感激 !