完整递推总结(包括各个板块)

递推是什么?

  • 递推是一种在数学中一种极为常见,极为普及,极为重要的解决问题的方法。
  • 递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算前面的一些项来得出序列中的指定项的值。
  • 要递推,先找到递推式。分析题意,一步步进行推理。其实就是找规律,只不过,比小学难得多。

递推的基本模型有:

  • Fibonacci
  • Hanoi塔
  • 分割平面
  • Catalan数
  • 第二类stirling数

基本模型来开会

1.Fibonacci

题目直通车

简介

斐波纳契数列原型:

1, 1, 2, 3, 5, 8, 13······
  • 狭义:最开始的两项为两个1,并且满足 f(n) = f(n - 1) + f(n - 2) 这个通项公式的数列;
  • 广义:满足 f(n) = f(n - 1) + f(n - 2) 这个通项公式的数列;

据说,是斐波纳契探究兔子问题的时候鼓捣了这个数列

AC代码亮相:

#include 
#include 
int a[25];
int main() {
	freopen ("rabbit.in", "r", stdin);
	freopen ("rabbit.out", "w", stdout);//文件输入输出
	int n;
	scanf("%d", &n);
	a[1] = a[2] = 1;初始化
	for (int i = 3; i <= n; i++) {
		a[i] = a[i - 1] + a[i - 2];//用递推式递推
	}
	printf("%d", a[n]);
	return 0;
} 

2.Hanoi塔

题目直通车

简介

一个很著名的益智游戏,汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。(:百度资料)

我们先来找个归路规律:

个数 : 1   2   3   4   ······
次数 : 1   3   7   15  ······

明白了?

次数有一个特点:等于 2 ^ 个数 - 1。

于是,代码简单明了:

#include 
#include 
int main() {
	int n;
	scanf("%d", &n);
	long long ans = 1;//保险,防止溢出
	for (int i = 1; i <= n; i++)  ans *= 2;计算
	printf("%lld", ans - 1);
	return 0;
}

3.分割平面

题目直通车

我们依然是先来找一下规律吧

曲线数  1   2   3   4  ······
平面数  2   4   8   14 ······

结果显而易见,加2,加4, 加6······

这就真成一道小学题
AC代码如下

#include 
#include 
int main() {
	int n;
	scanf("%d", &n);
	long long b = 2;
	long long sum = 2;//保险,防止溢出
	for (int i = 2; i <= n; i++) {
		sum += b;
		b += 2;
	}//递推
	printf("%lld", sum);
	return 0;
}

由此可见,递推的难点就是找递推式。一旦找出来,就可以轻而易举地解答此题了

4.Catalan数

题目直通车

卡特兰数又称卡塔兰数,卡特兰数是组合数学中一个常出现在各种计数问题中的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名。(:百度资料)

又是一个数列,如下:

1,1,2,5,14,42,132,429 ······
(注:此处从第0项开始)

是不是比上面的斐波纳契数列难得多?是不是还没有思路?没事,要是你全部都会,来学校干什么呢

递推式奉上:h(n)= h(0) * h(n-1) + h(1) * h(n-2) + ... + h(n-1)h(0) (其中n>=2)

很复杂?
经过错位相减的方法化简以后,是这样的:

h(n) = h(n-1) * (4n-2) / (n+1)。其中(n>1), h(0)=h(1)=1

于是,代码出炉:

#include 
#include 
long long h[35];
int main() {
	h[0] = h[1] = 1;
	int n;
	scanf("%d", &n);
	n -= 2;//为什么要减2我也不知道,减了就对了 -_-
	for (int i = 2; i <= n; i++) {
		h[i] = h[i - 1] * (4 * i - 2) / (i + 1);//递推
	}
	printf("%lld", h[n]);//注意占位符,输出
	return 0;
} 

5.第二类stirling数

题目直通车

简介

  • 在组合数学,Stirling数可指两类数,第一类Stirling数和第二类Stirling数,都是由18世纪数学家James Stirling提出的。
    Stirling数有两种,第一类和第二类Stirling数,它们自18世纪以来一直吸引许多数学家的兴趣,如欧拉、柯西、西尔沃斯特和凯莱等。后来哥本哈根(Copenhagen)大学的尼尔森(Niels Nielsen,1865-1931)提出了"Stirlingschen Zahlen erster Art" [第一类Stirling数]和"Stirlingschen Zahlen zweiter Art" [第二类Stirling数],首次把这两类数冠以「Stirling数」之名 。因为苏格兰数学家斯特林(J. Stirling, 1692-1770)首次发现这些数并说明了它们的重要性。
  • Stirling数的概念由J.Stirling于1730年提出,并在他的著作《Methodous Differentialis》中首次使用。
    1958年,Riordan首先应用s(n,k)和S(n,k)来分别表示第一类Stirling数和第二类Stirling数,1770年,L.Lagrenge推导出了第一类Stirling数的递推关系和数论的性质。而P.S.Lapace和A.Cauchy则在第二类Stirling数的逼近理论上取得了一些成果。1933年,Ch.Jordan在他的一篇论文中对Stirling数做了彻底的阐述,并给出了一些Stirling数的重要性质。(:百度资料)

题目讲解
but他们说GM说没用

话不多说,AC代码如下:

#include 
#include 
#include 
#include 
using namespace std;
const int MAXN = 30;
long long a[MAXN][MAXN];
int main() {
	int n, m;
	scanf("%d %d", &n, &m);//n是球数,m是盒子数
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= m; j++) {
			if (j == 1) a[i][j] = 1;//若只有一个盒子,就只有一种方法
			else if (i == j) a[i][j] = 1;//若盒子数与球数相等,也就一种方法
			else if (j == 0) a[i][j] = 0;//没盒子咋放
			else if (i < j) a[i][j] = 0;//盒子比球多,咋放嘛
			else if (i > j) {
				a[i][j] = j * a[i - 1][j] + a[i - 1][j - 1];递推
			} 
		}
	}
	printf("%lld", a[n][m]);
	return 0;
}

谢谢阅读

你可能感兴趣的:(递推)