第4章 递推法

4.1 递推法概述

设计思想
递推法(Recurrence Method)通过已知的初始条件和递推关系,逐步推导出问题的最终结果,常用于序列计算和分阶段问题求解。


示例:猴子和桃子问题

题目描述
猴子每天吃掉剩余桃子的一半再多吃一个,第 10 天只剩 1 个桃子,问最初有多少个桃子?

思路

  • 设 a[n] 为第 n 天结束后剩余的桃子数;

  • 已知 a[10] = 1;

  • 从后向前有递推关系:

    a[n] = (a[n+1] + 1) × 2
    

代码实现

// MonkeyPeach:计算第1天最初的桃子数
int MonkeyPeach(int days) {// days 表示总共天数,本题为 10int peaches = 1;           // 从第 days-1 天开始倒推到第 1 天for (int day = days - 1; day >= 1; day--) {// 根据递推关系 a[n] = (a[n+1] + 1) * 2// peaches 此时保存 a[n+1],更新后即为 a[n]peaches = (peaches + 1) * 2;}return peaches;            
}

整体解释
我们先假设最后一天剩余 1 个桃子,然后按照“后一天的桃子数加 1 再乘 2”这个公式,依次向前推算,每一步都将当前天的剩余数计算出来,循环结束后 peaches 即为第 1 天最初的桃子数。


4.2 数学序列中的递推法

4.2.1 斐波那契数列

题目描述
兔子繁殖问题:第 1、2 个月各有 1 对兔子,从第 3 个月起每月新增的兔子对数等于前两个月兔子对数之和,求第 n 个月的兔子对数。

递推关系

f(1) = 1,  f(2) = 1
f(n) = f(n-1) + f(n-2),  n ≥ 3

代码实现

// Fibonacci:计算第 n 个月的兔子对数
int Fibonacci(int n) {// 前两个月的兔子对数均为 1if (n <= 2) return 1;int prev = 1;   // f(i-2)int curr = 1;   // f(i-1)int next;       // f(i)// 从第 3 个月开始循环for (int i = 3; i <= n; i++) {next = prev + curr;   // 应用 f(i) = f(i-1) + f(i-2)prev = curr;          // 将 f(i-1) 赋值给 prevcurr = next;          // 将 f(i) 赋值给 curr}return curr;  // 返回 f(n)
}

整体解释
我们只记录前两项 prevcurr,每次计算新的一项 next,然后滚动更新这两个变量,最后 curr 存储的就是第 n 个月的兔子对数。此方法空间复杂度 O(1),时间复杂度 O(n)。


4.2.2 卡塔兰数

题目描述
凸 n 边形划分成三角形的不同方式数,第 n 个卡塔兰数 C(n) 满足:

C(0) = 1
C(n) = ∑_{i=0}^{n-1} C(i) × C(n-1-i),  n ≥ 1

代码实现

// Catalan:计算第 n 个卡塔兰数
int Catalan(int n) {// 分配数组存储 0...n 的 C 值int C[n+1];C[0] = 1;  // C(0) = 1// 依次计算 C(1) 到 C(n)for (int i = 1; i <= n; i++) {C[i] = 0;// 按定义累加for (int k = 0; k < i; k++) {C[i] += C[k] * C[i - 1 - k];}}return C[n];
}

整体解释
使用数组 C[] 自底向上存储卡塔兰数,通过两层循环,外层决定要计算的下标 i,内层按公式累加前面各项乘积,最终 C[n] 即为答案。时间复杂度 O(n²),空间复杂度 O(n)。


4.3 组合问题中的递推法

4.3.1 错排问题

题目描述
有 n 封信和 n 个信封,要求没有信件放入正确的信封,求错排方案数 D(n),递推关系:

D(1) = 0
D(2) = 1
D(n) = (n - 1) × (D(n-1) + D(n-2)),  n ≥ 3

代码实现

// Derangement:计算错排数 D(n)
int Derangement(int n) {if (n == 1) return 0;  // D(1) = 0if (n == 2) return 1;  // D(2) = 1int dn_2 = 0;  // D(n-2)int dn_1 = 1;  // D(n-1)int dn;        // D(n)// 从 n=3 开始迭代for (int i = 3; i <= n; i++) {dn = (i - 1) * (dn_1 + dn_2);dn_2 = dn_1;  // 滚动更新 D(n-2)dn_1 = dn;    // 滚动更新 D(n-1)}return dn;      // 返回 D(n)
}

整体解释
只需保留前两项 dn_2dn_1,用递推公式计算当前项 dn,再向后滚动即可,空间复杂度 O(1),时间复杂度 O(n)。


4.3.2 旋转万花筒

题目描述
起始有 4 个闪光点,每次旋转在每个分支末端增加 2 个闪光点,问 n 次旋转后总闪光点数。

代码实现

// Kale:计算旋转 n 次后的闪光点总数
int Kale(int n) {int lamps = 4;      // 初始闪光点数int addLamp = 2;    // 每个分支基础新增数for (int i = 1; i <= n; i++) {// 本次新增数量是上次的两倍addLamp *= 2;// 累加到总闪光点数lamps += addLamp;}return lamps;
}

整体解释
变量 addLamp 跟踪每次新增的闪光点数,每次翻倍后累加到 lamps,循环结束后 lamps 为旋转 n 次的总数。时间复杂度 O(n)。


4.4 拓展与演练

4.4.1 整数拆分(2 的幂次划分)

题目描述
将正整数 n 拆分为若干 2 的幂次之和,求拆分方案数 d(n),递推关系:

d(1) = 1  
d(2) = 2  
若 i 为奇数: d(i) = d(i - 1)  
否则:      d(i) = d(i - 1) + d(i / 2)

代码实现

// PowerSplit:计算 2 的幂次拆分方案数
int PowerSplit(int n) {int d[n + 1];   // 存储从 1 到 n 的方案数d[1] = 1;       // d(1) = 1d[2] = 2;       // d(2) = 2for (int i = 3; i <= n; i++) {if (i % 2 != 0) {// 奇数只能继承前一个的方案d[i] = d[i - 1];} else {// 偶数可在继承前一个方案基础上,加上包含 i/2 的拆分d[i] = d[i - 1] + d[i / 2];}}return d[n];
}

整体解释
用一维数组 d[] 自底向上记录每个 i 的方案数,遇到奇数直接复制,偶数则累加前一项和 i/2 的方案即可。时间复杂度 O(n),空间 O(n)。


4.4.2 捕鱼问题

题目描述
5 人轮流捕鱼,每人将看到的鱼分成 5 份,丢弃 1 条并带走 1 份,其余留给下一人,直到最后一人也按此规则操作,求最少的初始鱼数及每人捕鱼时看到的鱼数。

思路
从最小可能的初始鱼数开始尝试,依次验证每个人都能整除且满足规则。

代码实现

// GetFish:计算最少的初始鱼数
int GetFish(int nPeople) {int fish[5];         // fish[i] 记录第 i+1 个人见到的鱼数fish[0] = 1;         // 从最少 1 条开始尝试while (1) {fish[0]++;       // 逐次增加初始鱼数bool valid = true;// 验证每个人是否都能按规则操作for (int i = 1; i < nPeople; i++) {// (看见数 - 1) 必须能被 5 整除if ((fish[i - 1] - 1) % 5 != 0) {valid = false;break;}// 每人带走1份,留给下一个的人 = (fish[i-1]-1)/5*4fish[i] = (fish[i - 1] - 1) / 5 * 4;}if (valid) break;  // 全部满足则结束循环}return fish[0];
}

整体解释
数组 fish[] 存储每个人见到的鱼数,从第一个人开始试探最小初始值,每次尝试后向下验证,若所有人都满足“(见到数-1) 能被 5 整除”,则该初始值即为答案。时间复杂度较高,但能够找到最小解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/82072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可视化魔法指南

🎨 ECharts数据可视化魔法指南 🌟 ECharts:数据的艺术画笔 #mermaid-svg-ARwFHUrXBJ03Gpo9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ARwFHUrXBJ03Gpo9 .error-icon{fill:#552222;}#mermaid-svg-ARwFHUr…

SpringBoot学生宿舍管理系统开发实现

概述 一款基于SpringBoot框架开发的学生宿舍管理系统完整项目&#xff0c;该系统包含管理员、学生、宿管员和维修员四大角色模块&#xff0c;功能完善&#xff0c;非常适合作为设计或二次开发的基础项目。 主要内容 5.1 管理员功能模块 管理员登录界面采用验证码验证机制&a…

同步 / 异步、阻塞 / 非阻塞

前言 同步异步&#xff0c;在计算机科学中是一个非常重要的概念。作为一位软件开发工程师&#xff0c;我们每天都在和同步和异步打交道。 同步 同步-阻塞&#xff0c;顾名思义&#xff0c;就是同步和阻塞。调用方法后&#xff0c;必须等到结果返回&#xff0c;才能继续执行别…

AOP封装进行批量的数据查询并填充

在我们日常的项目开发中&#xff0c;我们经常会遇到这样的问题。我们有一张用户表&#xff0c;用户表中有用户ID和用户名称。我们其他表中会记录我们当前操作人的ID&#xff0c;一般&#xff0c;我们会记录一个创建人ID和修改人ID。那么&#xff0c;这个时候问题来了&#xff0…

Java学习手册:数据库事务相关知识

一、事务的概念与特性 概念 &#xff1a;事务是数据库中一系列操作的集合&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败&#xff0c;是一个不可分割的工作单位。例如&#xff0c;在银行转账系统中&#xff0c;从一个账户扣款和向另一个账户存款这两个操作必须作为…

java复杂度,包装类,泛型解析

如何衡量代码的好坏&#xff1f; 评价代码的好坏我们使用算法效率来判断&#xff0c;而算法效率分两种&#xff1a; 算法效率&#xff1a; 第一种是时间效率&#xff0c;第二种是空间效率&#xff0c;时间效率被称为时间复杂度&#xff0c;⽽空间效率被称作空间复杂度。 时间…

基于 SpringBoot + Vue 的校园管理系统设计与实现

一、项目简介 本系统以校园组织管理为主线&#xff0c;结合用户权限分离机制与模块化设计&#xff0c;实现对“单位类别、单位、通知推送、投票信息、用户回复”等内容的全流程管理&#xff0c;广泛适用于教育局、高校及下属组织的信息管理工作。 &#x1f3af; 项目亮点&…

iOS蓝牙技术实现及优化

以下是针对2025年iOS蓝牙技术实现的核心技术要点的深度解析&#xff0c;结合当前iOS 18&#xff08;推测版本&#xff09;的最新特性与开发实践&#xff0c;分模块结构化呈现&#xff1a; 一、硬件与协议层适配 BLE 5.3 支持 iOS 18默认支持蓝牙5.3协议&#xff0c;需注意&…

Qt 中实现观察者模式(Observer Pattern)

在 Qt 中实现**观察者模式(Observer Pattern)通常利用其内置的信号与槽(Signals & Slots)**机制,这是最符合 Qt 设计哲学的方式。以下是详细实现方法和关键点: —### 1. 观察者模式的核心思想- Subject(被观察者):维护一个观察者列表,在状态变化时通知观察者。- …

写程序,统计两会政府工作报告热词频率,并生成词云

import jieba from collections import Counter from wordcloud import WordCloud import matplotlib.pyplot as pltdef generate_wordcloud():try:# 读取文本文件with open(E:\\桌面\\s.txt, r, encodingutf-8) as file:text file.read()# 中文分词words jieba.lcut(text)# …

【Science Advances】普林斯顿大学利用非相干光打造可重构纳米光子神经网络

(导读 ) 人工智能对计算性能需求剧增&#xff0c;电子微处理器发展受功耗限制。光学计算有望解决这些问题&#xff0c;光学神经网络&#xff08;ONNs&#xff09;成为研究热点&#xff0c;但现有 ONNs 因设计缺陷&#xff0c;在图像分类任务中精度远低于现代电子神经网络&#…

gin + es 实践 01

项目结构说明 目录结构概览 Go-ES 项目采用领域驱动设计&#xff08;DDD&#xff09;架构&#xff0c;目录结构清晰&#xff0c;各层次职责分明。以下是项目的主要目录结构&#xff1a; go-es/ ├── cmd/ # 应用程序入口 │ └── api/ …

如何构建直播美颜SDK?从美颜API调用逻辑到GPU优化实战

随着短视频和直播行业的爆发&#xff0c;美颜SDK已成为各大直播平台的“标配”。从基础的磨皮、美白&#xff0c;到如今的AI滤镜、虚拟形象&#xff0c;这些功能的背后都离不开高效的美颜SDK支持。那么&#xff0c;如何构建一款性能优越、体验流畅的直播美颜SDK呢&#xff1f;本…

高组装导轨的特点

高组装导轨通常是四列式单圆弧齿形接触直线导轨&#xff0c;具有整合化的结构设计&#xff0c;适用于重负荷和精密应用。与其它直线导轨高组装导轨提升了负荷与刚性能力&#xff0c;具备四方向等负载特色和自动调心功能&#xff0c;能够吸收安装面的装配误差&#xff0c;达到高…

2025-05-07-FFmpeg视频裁剪(尺寸调整,画面比例不变)

原比例如图 原比例如图裁剪后的比例 代码&#xff1a; 方法一&#xff1a;极速 ffmpeg -i input.mp4 -vf "crop1080:750:0:345" -c:v libx264 -preset ultrafast -c:a copy output.mp4关键参数说明&#xff1a; vf “crop宽:高❌y”&#xff1a;定义裁剪区域。 …

一个.Net开源的协作办公套件,包括文档、表格、演示文稿和表单

从零学习构建一个完整的系统 推荐一个开源的文档协作办公套件&#xff0c;可以很好的满足团队对方便、高效、安全的方式来处理文档工作&#xff0c;促进团队协作和信息共享。 项目简介 ONLYOFFICE 是一个开源的办公套件&#xff0c;包括文档、表格、演示文稿和表单等应用程序…

虚幻基础:硬件输入

文章目录 triggered&#xff1a;按下一直触发 等于tickcompleted&#xff1a;必须等到triggered结束后 才触发松下triggered结束 默认按键触发顺序按下&#xff1a;触发两个先 Started后 Triggered 松开Completed 触发器&#xff1a;用于修改triggered 触发和结束驱动阈值&…

Python中的global与nonlocal关键字详解

一、前言 在Python编程中&#xff0c;变量作用域是一个非常重要的概念。对于初学者来说&#xff0c;经常会遇到在函数内部无法修改外部变量的问题。这时候&#xff0c;global和nonlocal关键字就能派上用场了。本文将详细介绍这两个关键字的用法、区别以及适用场景&#xff0c;…

vue-qr生成的二维码增加下载功能

大家好&#xff01;今天给大家分享一个超实用的前端小技巧——如何在 Vue 项目中生成二维码并实现下载功能。这个功能在分享链接、活动推广等场景特别有用&#xff0c;一起来学习吧&#xff01; &#x1f50d; 功能预览 使用 vue-qr 生成美观二维码点击按钮即可下载 PNG 格式的…

嵌入式C进阶路线指南

嵌入式是工科&#xff0c;工科讲究实践。说的再多、懂得再多&#xff0c;不能做出实际的东西&#xff0c;是没有意义的。学习嵌入式的核心原则之一就是多动手写代码。另外还有一个原则就是&#xff1a;从浅到深学习。接下来的内容将贯彻这两个原则。最后强调一点&#xff0c;各…