递推总结
首先:
什么是递推
递推
中文名 | 外文名 |
---|---|
递推 | The Recursive |
定义
“递推是按照一定的规律来计算序列中的每个项,通常是通过计算前面的一些项来得出序列中的指定项的值。其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。”
“所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果。其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定。
从已知条件出发逐步推到问题结果,此种方法叫顺推。
从问题出发逐步推到已知条件,此种方法叫逆推。
无论顺推还是逆推,其关键是要找到递推式。这种处理问题的方法能使复杂运算化为若干步重复的简单运算,充分发挥出计算机擅长于重复处理的特点。
递推法是一种重要的数学方法,在数学的各个领域中都有广泛的运用,也是计算机用于数值计算的一个重要算法。
递推算法的首要问题是得到相邻的数据项间的关系(即递推关系)。递推算法避开了求通项公式的麻烦,把一个复杂的问题的求解,分解成了连续的若干步简单运算。一般说来,可以将递推算法看成是一种特殊的迭代算法。”
总而言之,递推的核心思想是找出
递推式
言归正传,五种递推模型如下:
五种递推模型
斐波拉契 Fibonacci
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。
数列为:1、1、2、3、5、8、13、21、34、……
在数学上,斐波那契数列以如下被以递推的方法定义:*F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N)**在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从 1963 年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
数列已经给出,递推式即为F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*) 边界条件为F(1)=1,F(2)=1
代码如下 :
#include<cstdio>
#include<cmath>
int main()
{
freopen("rabbit.in","r",stdin);//注意看题!
freopen("rabbit.out","w",stdout);
int n;
long long f[100005];
f[1]=1;
f[2]=1;
scanf("%d",&n);
for(int i=3;i<=n;i++)
{
f[i]=f[i-1]+f[i-2];
}
printf("%d",f[n]);
return 0;
}
汉诺塔
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
不管这个传说的可信度有多大,如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。n=64时,
假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:
18446744073709551615秒这表明移完这些金片需要5845.54亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。
数列模拟后可以得知 : 1,3,7,15,31,63… …
递推式为 H[i]=H[i-1]2+1 边界条件为H[1]=1*
代码如下:
#include <cstdio>
#include <iostream>
int main() {
long long n,H[68];
scanf("%lld",&n);
H[1]=1;
for(int i=2;i<=n;i++) {
H[i]=H[i-1]*2+1;
}
printf("%lld",H[n]);
return 0;
}
分割平面
这道题可以通过图来算
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8GuTFFk-1592638665357)(http://media.openjudge.cn/images/upload/1523337982.jpg “乱动什么鼠标”)]
看看就知道 数列为 2,4,8,14
数列已经给出,递推式即为a[i]=a[i-1]+2*(i-1); 边界条件为a[1]=2;
代码如下:
#include <cstdio>
int main() {
int n,a[46346];
scanf("%d",&n);
a[1]=2;
for(int i=2;i<=n;i++) {
a[i]=a[i-1]+2*(i-1);
}
printf("%d",a[n]);
return 0;
}
Catalan
卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常见数列,前几项为(从第零项开始) : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452… …
这里因为表示按照上述规则划分的三角形区域个数,那么我们随便选一条多边形的一条边作为基边,那么
再在剩余的n-1个点中选一个点,我们把所选的一条边的两点分别与所选的那一点连接起来,那么多边形被划
分成3部分,一部分有k+1条边,一部分有3条边,另一部分有n-k+1条边,那么这样就划分成了子问题了,所
以按照这个思路可以证明递推式成立。
已经给出了数列及推导,递推式与边界条件为 :
a[0] = 0, a[1] = 0, a[2] = 1, a[3] = 1;
for(int i = 4; i <= n; i++) {
for(int j = 2; j <= i - 1; j++)
a[i] += (a[j] * a[i - j + 1]);
}
代码如下 :
#include <cstdio>
const int MAXN = 45;
long long a[MAXN];
int main() {
int n;
scanf ("%d", &n);
a[0] = 0, a[1] = 0, a[2] = 1, a[3] = 1;
for(int i = 4; i <= n; i++) {
for(int j = 2; j <= i - 1; j++)
a[i] += (a[j] * a[i - j + 1]);
}
printf("%lld
", a[n]);
return 0;
}
第二类stirling
第二类Stirling数,其表示将n个不同的元素分成m个集合的方案数。
求法
一般有两种求法。
递推:
S(n,m)=S(n−1,m−1)+mS(n−1,m)
即讨论第一个球是否单独在一个盒子里面。
如果不独占一盒,那么把这个球放进任一个盒子,这个盒子就相当于与其他的盒子不同,那么在乘答案的时候就要多乘一个m.
容斥原理:
S(n,m)=1m!∑k=0m(−1)kC(m,k)(m−k)n
即枚举空盒的个数,剩下的随意放置,由于盒子是相同的最后要除以m!
注意到这个式子是一个卷积,所以可以在O(nlogn)内求出S(n,0),S(n,1)…
性质=0kS(k,i)×i!×C(n,i)nk=
只有一个公式
很好理解,左边就是k个球可以任意放置在n个盒子里。
右边就是枚举非空盒子的数量i,那么把k个球放在i个盒子(盒子不同,需要乘上一个i!)里面再乘上选出i个非空盒子的方案数。
代码如下:
#include <cstdio>
const int MAXN = 25;
long long a[MAXN][MAXN];
int main() {
int n, m;
scanf ("%d %d", &n, &m);
for(int i = 1; i <= 20; i++) {
a[i][1] = 1;
a[i][i] = 1;
}
for(int i = 2; i <= m; i++)
for(int j = i + 1; j <= n; j++)
a[j][i] = a[j - 1][i - 1] + i * a[j - 1][i];
printf("%lld", a[n][m]);
return 0;
}