【算法】递推 1

递推 1

引入

我们常常说的斐波那契数列大家肯定知道,一开始学 OI 时大多数人都是用循环来解决的(c = a + b, a = b, b = c)。但你有没有想过一点,如果再复杂一点,那么代码会很难写。下面就介绍一种算法——递推。

概念

递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算前面的一些项来得出序列中的指定项的值。无论顺推还是逆推,其关键是要找到递推式。这种算法能使复杂运算化为若干步重复的简单运算。

分析

我们就拿最典型的斐波那契数列来说,它的公式为 {if 1i2fi=1if i3fi=fi1+fi2推理过程),如果我们要求斐波那契数列的第 n 项,那该怎么办?

我们先建立一个 f 数组,把 f0,f1 的初始值赋值为 1。然后跑 for 循环遍历 2n,对于每个 i 都要进行一次递推(f[i] = f[i - 1] + f[i - 2])。

代码如下:

f[0] = f[1] = 1;
for (int i = 2; i <= n; ++ i) {
  f[i] = f[i - 1] + f[i - 2];
}

递推其实就是数组 + 循环,只要推出了递推式,什么都好办了。

例题 1

N 级台阶,你一开始在底部,每次可以向上迈 1K 级台阶,问到达第 N 级台阶有多少种不同方式 mod100003。(1N1000001K100

我们发现,第 i 级台阶可以从 i1,i2,,iK 级台阶迈上来。当 K=2 时,是不是就是斐波那契数列?没错,这题是斐波那契数列进阶版。

我们先赋初始值(f0=f1=1),第一层循环跟普通斐波那契一样,第二层套一个 1K 的循环(因为第 i 级台阶可以从 i1,i2,,iK 级台阶迈上来),如果 ji,那么 fi 就为 fi+fij(原理跟普通斐波那契一样),注意取模

代码:

f[0] = f[1] = 1;
for (int i = 2; i <= n; ++ i) {
  for (int j = 1; j <= k; ++ j) {
    if (j <= i) {
      f[i] = (f[i] + f[i - j]) % kMod; // 注意取模,kMod 是模数(100003)
    }
  } 
}
f[n] %= kMod; // 注意取模
cout << f[n] << '\n';

例题 2

派蒙给了你两个数 n,xx 初始值为 1,还给了你两种操作:1. x2x(把 x 变为 2x(相当于 2×x))。2. xx+1(把 x 变为 x+1)。现在派蒙想知道至少花多少步才能把 x 变成 n。(1n105

我们可以发现数字 P 可以从 P2P1 得来,所以得到递推式 fi=min(fi1+1,fi÷2+1)。但这个递推式只对于偶数 i,我们发现,如果 Pmod2=0,那么把 P 变成 P+1 需要 1 步 (xx+1)。所以对于每个奇数 i,有 fi=fi1+1

for (int i = 2; i <= n; i += 2) {
  f[i] = min(f[i - 1] + 1, f[i / 2] + 1);
  f[i + 1] = f[i] + 1;
}
cout << f[n] << '\n';

例题 3

给定一个 1×2n 的矩阵,现让你自由地放入红色算筹和黑色算筹,使矩阵平衡(即 i[1,2n]1i 格中红色算筹个数大于等于黑色算筹)。问有多少种方案满足矩阵平衡(注意红色算筹和黑色算筹的数量必须相等)。(1n100

首先观察数据范围,1n100,用 O(n2) 递推(又称 DP,这东西后面会学)。

fi,j 表示前 i 个算筹中放 j 个红色算筹的方案数,可以得出 fi,j=fi1,j+fi1,j1 [ji2](读者可自证)。

代码不放了(递推式都告诉你了)。

总结

递推可以解决很多最大最小问题,但有人发明了高级的递推——DP……

(后面会有递推 2,讲的是比较难的递推)

posted @   beautiful_chicken233  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示