当前位置:首页 > 技术 > 正文内容

递推与递归算法的典型实现与代码优化

访客 技术 2026年10月5日 1

一、多状态同步迭代

在处理具有多个相互依赖变量的递推问题时,直接使用连续赋值容易导致状态覆盖错误。通过引入临时缓存或显式的状态转移步骤,可以确保每一轮迭代的输入值均来自上一轮的正确结果。该模型常用于模拟复杂系统的状态演进。

#include <iostream>
int main() {
    int iterations;
    std::cin >> iterations;
    long long state_a = 1, state_b = 0, state_c = 0;
    for (int k = 0; k < iterations; ++k) {
        long long next_a = state_a + state_b;
        long long next_b = state_c;
        long long next_c = next_a + state_c;
        state_a = next_a;
        state_b = next_b;
        state_c = next_c;
    }
    std::cout << state_a << std::endl;
    return 0;
}

二、斐波那契数列的线性递推

斐波那契型数列是递推算法的基础原型。利用数组存储中间计算结果,可以将时间复杂度从指数级优化至线性级。此处采用定长容器进行状态缓存,直接输出指定位置的序列值。

#include <iostream>
#include <vector>
int main() {
    int limit;
    std::cin >> limit;
    std::vector<long long> fib(limit + 1, 0);
    fib[1] = fib[2] = 1;
    for (int idx = 3; idx <= limit; ++idx) {
        fib[idx] = fib[idx - 1] + fib[idx - 2];
    }
    std::cout << fib[limit] << std::endl;
    return 0;
}

三、累加型递推关系

当递推公式呈现为 $a_i = a_{i-1} + i$ 形式时,实质上是在构建等差数列的前缀和。该逻辑可直接转化为单向累加循环,无需额外开辟数组空间,实现空间复杂度的常数级优化。

#include <iostream>
int main() {
    int upper_bound;
    std::cin >> upper_bound;
    long long accumulator = 2;
    for (int step = 2; step <= upper_bound; ++step) {
        accumulator += step;
    }
    std::cout << accumulator << std::endl;
    return 0;
}

四、互质判定与辗转相除法

欧几里得算法通过不断取模替换较大值,快速收敛至最大公约数。若最终公约数为1,则两数互质。该实现通过迭代更新避免了递归调用的栈开销。

#include <iostream>
int main() {
    long long x, y;
    std::cin >> x >> y;
    while (y != 0) {
        long long remainder = x % y;
        x = y;
        y = remainder;
    }
    if (x == 1) std::cout << "Yes" << std::endl;
    else std::cout << "No" << std::endl;
    return 0;
}

五、汉诺塔问题的分治递归

汉诺塔是递归思想的经典应用场景。将 $n$ 个圆盘从起始柱移动至目标柱,可拆解为:先将 $n-1$ 个圆盘移至辅助柱,移动底部最大圆盘,再将 $n-1$ 个圆盘从辅助柱移至目标柱。边界条件为 $n=0$ 时直接返回。

#include <iostream>
using namespace std;
void move_disks(int count, char source, char aux, char target) {
    if (count <= 0) return;
    move_disks(count - 1, source, target, aux);
    cout << source << "->" << count << "->" << target << endl;
    move_disks(count - 1, aux, source, target);
}
int main() {
    int total_disks;
    char rod_a, rod_b, rod_c;
    cin >> total_disks >> rod_a >> rod_b >> rod_c;
    move_disks(total_disks, rod_a, rod_b, rod_c);
    return 0;
}

六、受限步长的路径计数

在步长受限的移动问题中,到达第 $i$ 个位置的方案数等于从合法前驱位置转移而来的方案之和。通过预设初始边界条件,即可利用状态转移方程完成动态规划填表。

#include <iostream>
int main() {
    int target;
    std::cin >> target;
    long long dp[1005] = {0};
    dp[2] = 1; 
    dp[3] = 1;
    for (int pos = 4; pos <= target; ++pos) {
        dp[pos] = dp[pos - 2] + dp[pos - 3];
    }
    std::cout << dp[target] << std::endl;
    return 0;
}

七、逆向思维倒推模型

对于已知最终状态反推初始状态的题目,正向计算往往复杂,而从终点向起点逆向还原则逻辑清晰。每一步执行逆运算,即可高效还原原始数值。

#include <iostream>
int main() {
    int steps;
    std::cin >> steps;
    long long value = 1;
    for (int i = 1; i < steps; ++i) {
        value = (value + 1) << 1;
    }
    std::cout << value << std::endl;
    return 0;
}

八、阶梯攀登方案统计

每次允许攀登1阶或2阶楼梯时,到达第 $n$ 阶的方案数符合斐波那契数列变体。通过数组记忆化中间结果,避免重复子问题的冗余计算。

#include <iostream>
int main() {
    int floors;
    std::cin >> floors;
    long long ways[1005] = {0};
    ways[1] = 1; 
    ways[2] = 2;
    for (int i = 3; i <= floors; ++i) {
        ways[i] = ways[i - 1] + ways[i - 2];
    }
    std::cout << ways[floors] << std::endl;
    return 0;
}

九、最大公约数直接输出

与互质判定类似,若仅需获取两数的最大公约数,可直接在循环结束后输出收敛值。该实现采用模运算迭代,具备对数级时间复杂度。

#include <iostream>
int main() {
    long long num_a, num_b;
    std::cin >> num_a >> num_b;
    while (num_b != 0) {
        long long temp = num_a % num_b;
        num_a = num_b;
        num_b = temp;
    }
    std::cout << num_a << std::endl;
    return 0;
}

十、带参依赖的动态规划

当递推关系涉及外部参数且序列间存在交叉引用时,需维护多个状态数组并严格控制访问边界。通过预先填充基准区间,并按序更新衍生序列,可处理复杂的参数化递推逻辑。

#include <iostream>
#include <vector>
int main() {
    int threshold, multiplier, range;
    std::cin >> threshold >> multiplier >> range;
    std::vector<long long> seq_a(range + 1, 0);
    std::vector<long long> seq_b(range + 1, 0);
    for (int i = 0; i < threshold; ++i) seq_a[i] = 1;
    for (int i = threshold; i <= range; ++i) {
        seq_a[i] = seq_a[i - 1] + seq_b[i - 2];
        seq_b[i] = seq_a[i - threshold] * multiplier;
    }
    std::cout << seq_a[range] << std::endl;
    return 0;
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。