【算法】递推 1
递推 1
引入
我们常常说的斐波那契数列大家肯定知道,一开始学 OI 时大多数人都是用循环来解决的(c = a + b, a = b, b = c
)。但你有没有想过一点,如果再复杂一点,那么代码会很难写。下面就介绍一种算法——递推。
概念
递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算前面的一些项来得出序列中的指定项的值。无论顺推还是逆推,其关键是要找到递推式。这种算法能使复杂运算化为若干步重复的简单运算。
分析
我们就拿最典型的斐波那契数列来说,它的公式为 (推理过程),如果我们要求斐波那契数列的第 项,那该怎么办?
我们先建立一个 数组,把 的初始值赋值为 。然后跑 for
循环遍历 ,对于每个 都要进行一次递推(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
有 级台阶,你一开始在底部,每次可以向上迈 级台阶,问到达第 级台阶有多少种不同方式 ()。(,)
我们发现,第 级台阶可以从 级台阶迈上来。当 时,是不是就是斐波那契数列?没错,这题是斐波那契数列进阶版。
我们先赋初始值(),第一层循环跟普通斐波那契一样,第二层套一个 的循环(因为第 级台阶可以从 级台阶迈上来),如果 ,那么 就为 (原理跟普通斐波那契一样),注意取模。
代码:
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
派蒙给了你两个数 , 初始值为 ,还给了你两种操作:1. (把 变为 (相当于 ))。2. (把 变为 )。现在派蒙想知道至少花多少步才能把 变成 。()
我们可以发现数字 可以从 和 得来,所以得到递推式 。但这个递推式只对于偶数 ,我们发现,如果 ,那么把 变成 需要 步 ()。所以对于每个奇数 ,有 。
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
给定一个 的矩阵,现让你自由地放入红色算筹和黑色算筹,使矩阵平衡(即 , 格中红色算筹个数大于等于黑色算筹)。问有多少种方案满足矩阵平衡(注意红色算筹和黑色算筹的数量必须相等)。()
首先观察数据范围,,用 递推(又称 DP,这东西后面会学)。
令 表示前 个算筹中放 个红色算筹的方案数,可以得出 (读者可自证)。
代码不放了(递推式都告诉你了)。
总结
递推可以解决很多最大最小问题,但有人发明了高级的递推——DP……
(后面会有递推 2,讲的是比较难的递推)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效