• 递推总结


    递推总结

    首先:

    什么是递推

    递推

    中文名 外文名
    递推 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=

    只有一个公式

    nk=i=0kS(k,i)×i!×C(n,i)n^k=sum_{i=0}^k S(k,i)×i!×C(n,i)

    很好理解,左边就是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;
    }
    
  • 相关阅读:
    通过 WakaTime 统计你写代码的时长
    CCF 202012-3 带配额的文件系统
    1
    prometheus 获取cpu利用率
    springboot使用@data注解,减少不必要代码-lombok插件
    django官方教程部署simpleui时候发现加载不到静态文件解决办法
    echarts关系图研究01
    SpringBoot代码方式禁用Druid Monitor
    virtualbox给已有磁盘扩展容量
    centos7 ssh免密登录配置
  • 原文地址:https://www.cnblogs.com/cqbz-ChenJiage/p/13504675.html
Copyright © 2020-2023  润新知