不要在意这些细节。
说实话, 这篇博客想了很久, 不知道写什么(毕竟是人生第一篇博客), 最后才决定·, 来个入门的——递推总结!
首先,
递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算前面的一些项来得出序列中的指定项的值。
“递推是按照一定的规律来计算序列中的每个项,通常是通过计算前面的一些项来得出序列中的指定项的值。其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。”
“所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果。其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定。 从已知条件出发逐步推到问题结果,此种方法叫顺推。 从问题出发逐步推到已知条件,此种方法叫逆推。 无论顺推还是逆推,其关键是要找到递推式。这种处理问题的方法能使复杂运算化为若干步重复的简单运算,充分发挥出计算机擅长于重复处理的特点。 递推法是一种重要的数学方法,在数学的各个领域中都有广泛的运用,也是计算机用于数值计算的一个重要算法。 递推算法的首要问题是得到相邻的数据项间的关系(即递推关系)。递推算法避开了求通项公式的麻烦,把一个复杂的问题的求解,分解成了连续的若干步简单运算。一般说来,可以将递推算法看成是一种特殊的迭代算法。”
总而言之,递推的核心思想是找出递推式
斐波那契,即满足等式 a[i] = q * a[i - x] + p * a[i - y] 的递推模型,是最基础的递推模型。
热带森林中有一种昆虫,这种昆虫的繁殖能力很强。每对成虫每过x个月产y对卵,每对卵要过2个月长成成虫。假设每个成虫不死,第一个月只有一对才从卵长成的
成虫,且卵长成成虫后不会立即产卵,要过x个月才开始产卵),问过z个月,即到z+1个月时,共有成虫多少对?
第1行:3个整数x, y, z (1<=x<=z<=50, 1<=y<=10)
第1行:1个整数,表示到z+1个月时,有成虫多少对?
2 3 10
40
令a[i]储存将会在第i月产卵的昆虫数,则有:
答案即 将z到z-x的昆虫数的累加结果
显然
a[i + 2] += a[i] * y; //产卵
a[i] += a[i - 2]; // 成虫数传递
于是得到代码:
#include
long long a[105], ans;
int x, y, z;
int main() {
scanf("%d %d %d", &x, &y, &z);
a[1] = 1;
for (int i = x + 1; i <= z + 1; i++) {
a[i + 2] += a[i - x] * y;//产卵
a[i] += a[i - x];//成虫数
}
for (int i = 0; i < x; i++) {
ans += a[z + 1 - i];
}
printf("%lld",ans);
return 0;
}
Catalan数是解决正n边形的由n-3条不交叉对角线构成n-2个三角形的总数问题,时间复杂度通常为n方。 分析:
令Catalan数c[n],则n+1边形可确认一个三角形,将答案累加即可。
设n+1、1、i号点相连,则方法数为c[n-i+1] * c[i]
为了计算方便,令c[2]=1;
Czyzoiers 都想知道小 x 为什么对鸡蛋饼情有独钟。经过一番逼问,小 x 道出了实情:因为他喜欢圆。
最近小 x 又发现了一个关于圆的有趣的问题:在圆上有 2N 个不同的点,小 x 想用 N 条线段把这些点连接起来(每个点只能连一条线段), 使所有的线段都不相交,他想知道这样的连接方案有多少种?
有且仅有一个正整数N。(N≤2999)
要求的方案数(结果mod 100000007)。
24
4057031
思路一样,设1号和i号相连,则数量为c[i-2] * c[n-i-1];
代码:
#include
const int MAXN = 3005, MOD = 100000007;//静态定义
long long a[MAXN] = {1, 1, 2};
int n;
int main() {
scanf("%d", &n);
for (int i = 3; i <= n; i++) {
for (int j = 0; j < i; j++) {
a[i] += a[j] * a[i - j - 1] % MOD;
}
a[i] %= MOD;
}
printf("%lld", a[n]);
return 0;
}
第二类stirling数是解决将n个不同小球放入m个相同盒子并没有空盒的问题。
分析: 令第二类stirling数为s[n][m],求s[n+1][m] 分成两类: (1):若n个球放入m个盒子,则第n+1个球可放入任意盒子,方法数:ms[n][m]; (2):若n个球放入m-1个盒子,则第n+1个球独占一个盒子,方法数s[n][m-1]; 综上,得到规律:s[n][m] = s[n-1][m-1] + ms[n-1][m];
n个各不相同球放入m个相同的盒子里,球全部放完后,要求最后没有空盒!求不同的放法总数。
一行两个数n和m
n表示球数,m表示盒子数
(0<n≤20)(0≤m≤20)
不同且合理的放法总数
3 2
3
第二类stirling数
真是一道良心题, 把核心都说出来了(第二类stirling数), 那我也没什么好说的了…
代码如下:
#include
const int MAXN = 25;
long long a[MAXN][MAXN];
int n, m;
int main() {
scanf("%d %d", &n, &m);
a[1][1] = 1;
a[2][1] = 1;
a[2][2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= m; j++) {
a[i][j] = j * a[i - 1][j] + a[i - 1][j - 1];
}
}
printf("%lld", a[n][m]);
return 0;
}
有一个美妙的传说~
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
这就是汉诺塔的由来
问题的提出:Hanoi塔由n个大小不同的圆盘和三根木柱a,b,c组成。开始时,这n个圆盘由大到小依次套在a柱上,如图所示。
要求把a柱上n个圆盘按下述规则移到c柱上:
规则:
(1)、一次只能移一个圆盘;
(2)、圆盘只能在三个柱上存放;
(3)、在移动过程中,不允许大盘压小盘。
问将这n个盘子从a柱移动到c柱上,总计需要移动多少个盘次?
一个数n(1≤n≤63)
一个数,总计需要移动多少个盘次
3
7
设h(n)为第n个盘子从a柱移到c柱所需移动的盘次.显然,当n = 1时,只需把a柱上的盘子直接移动到c柱就可以了,故h(1) = 1.
当n = 2时,先将a柱上面的小盘子移动到b柱上面去;然后将大盘子从a柱移到c柱:最后,将b柱上的小盘子移到c柱上,共三个盘次,故h(2) = 3.
以此类推,当a柱上有n个盘子,总是先借助c柱把上面的n - 1个盘子移动到b柱,然后再把a柱最下面的盘子移动到c柱上;再借助a柱把b柱上的n - 1个盘子移动到c柱上;总共移动h(n - 1) + 1 + h(n - 1)个盘次.所以可得到h(n) = 2h(n - 1) + 1,边界条件:h(1) = 1.
于是得到代码:
#include
const int MAXN = 65;//因为 n<=63, 所以要开long long
long long h[MAXN] = {0, 1};
int n;
int main() {
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
h[i] = 2 * h[i - 1] + 1;
}
printf("%lld", h[n]);
return 0;
}
当然也可以用公式h(n) = 2 ^ n - 1来做:
#include
long long My_Pow(int a, int b) {//函数
long long tot = 1;
for (int i = 1; i <= b; i++) {
tot *= a;
}
return tot;
}
int main() {
int n;
scanf("%d", &n);
long long ans = My_Pow(2, n) - 1;
printf("%lld", ans);
return 0;
}
很简单的一道数学题, 用数学归纳法就不难得出:f(n) = n * (n + 1) / 2 + 1.
设有n条封闭曲线画在平面上,而任何两条封闭曲线恰好相交于两点,且任何三条封闭曲线不相交于同一点,问这些封闭曲线把平面分割成的区域个数。
一个数n(1≤n≤46341)
一个数,这些曲线把平面分割成的个数总和
3
8
当平面上已有n - 1条曲线将平面分割成a(n - 1)个区域后,第n条曲线每与曲线相交一次,就会增加一个区域,因为平面上已经有了n - 1条封闭曲线,且第n条曲线与已有的每一条封闭曲线恰好交于两点,且不会与任两条曲线交于同一点,故平面上增加 2(n - 1) 个区域,加上已有的 a(n - 1) 个区域,一共有a(n - 1) + 2(n - 1) 个区域.所以本题的递推关系是 a(n) = a(n - 1) + 2 (n - 1),边界条件是a(1) = 1.
代码如下:
#include
const int MAXN = 46350;
int a[MAXN] = {0, 2};
int n;
int main() {
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
a[i] = a[i - 1] + 2 * (i - 1);
}
printf("%d", a[n]);
return 0;
}
当然,也可以找规律,不难得出:a(n) = n * (n - 1) + 2.
那就很简单了, 代码如下:
#include
int main() {
int n;
scanf("%d", &n);
printf("%lld", n * n - n + 2);
return 0;
}