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(i1)+f(i2)
初始条件: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 ( n 2 ) O(n^2) O(n2)

递推思想的运用

错位排序

杨辉三角

你可能感兴趣的:(数据结构与算法,c++,c++,算法,递归递推)