c++算法初级8——递推与递归
c++算法初级8——递推与递归
文章目录
- c++算法初级8——递推与递归
-
- 递推
- 递推思想的运用
-
- 错位排序
- 杨辉三角
递推
递推思想:
根据已有的东西一点点地推出未知的东西。
使用递推解题三步骤:
- 数学建模
- 找出递推式和初始条件
- 写出代码。
张爽的青蛙(斐波那契)问题:地上有n个石头从左到右排成一排,张爽同学养的青蛙要从第一个石头跳到最后一个石头上,每次可以选择向右跳一格或者跳两格,问总共有多少种不同的走法?
递推表达式:设跳到第i格有f(i)f(i)f(i)个跳法,则f(i)=f(i−1)+f(i−2)f(i)=f(i-1)+f(i-2)f(i)=f(i−1)+f(i−2)
初始条件:f[1] = f[2] = 1。因为从1走到1只有一种方案(呆在原地不动),从1走到2也只有一种方案(走一格);
代码:
# include "bits/stdc++.h"
using namespace std;
const int MOD = 998244353; // 答案对998244353取模。
int k, f[1000010];int main()
{cin >> k;f[1] = 1;f[2] = 1;for (int i = 3; i <= k; i++){f[i] = (f[i - 1] + f[i - 2]) % MOD;}cout << f[k] << endl;return 0;
}
卡特兰数问题:由n对括号组成的括号序列,有多少种是合法的括号序列?答案对998244353取模。
什么是合法的括号序列?其定义如下:
空序列是合法的括号序列
如果A是合法的括号序列,那么(A)是合法的括号序列
如果A和B是合法的括号序列,那么AB也是合法的括号序列
简单通俗地讲,合法的括号序列就是:任何一个左括号都必须有与之对应的右括号,任何一个右括号都必须有与之对应的左括号。
比如:
()(()(()))是合法的括号序列
)(不是合法的括号序列,因为第一个右括号没有与之对应的左括号
(()))不是合法的括号序列,因为最后一个右括号没有与之对应的左括号
类似的,如果我们想用递推解决问题,我们就要找到递推式。首先开一个数组int f[n],用f[i]来表示i对括号能够组成多少种合法的括号序列。那么,怎么根据f[0], f[1], f[2], …, f[k-1]的值推出f[k]的值呢?
我们继续使用分类讨论的思想:由于合法括号序列的最后一个字符一定是右括号,不妨假设最终的括号序列长成这个样子:A(B)。其中,A和B都是合法括号序列(注意A和B可以是空序列)。
我们把最终的序列分成k种:
A由0对括号组成,B由k-1对括号组成,这样的序列有f[0] * f[k-1]种
A由1对括号组成,B由k-2对括号组成,这样的序列有f[1] * f[k-2]种
A由2对括号组成,B由k-3对括号组成,这样的序列有f[2] * f[k-3]种
……
A由m对括号组成,B由k-1-m对括号组成,这样的序列有f[m] * f[k-1-m]种
……
A由k-1对括号组成,B由0对括号组成,这样的序列有f[k-1] * f[0]种
由此,就得到了递推式
初始条件:
f(0)=1,,因为0对括号只能组成一种括号序列(空序列)
代码
# include"bits/stdc++.h"
using namespace std;
const int MOD = 998244353;
int n, f[100010];int main() {cin >> n;f[0] = 1;for (int i = 1; i <= n; i++) {for (int j = 0; j < i; j++) {f[i] = (f[i] + 1ll * f[j] * f[i - j - 1]%MOD) % MOD;}}cout << f[n] << endl;return 0;
}
时间复杂度O(n2)O(n^2)O(n2)