【算法进阶2-动态规划】斐波那契数列(递归调用、动态规划)、钢条切割问题(自定而下实现、自底向上、切割方案)

1 斐波那契数
2 钢条切割问题
2.1 最优解情况
2.2 钢条切割问题之自定而下实现
2.3 钢条切割问题之自底向上实现
2.4 钢条切割问题-重构解-切割方案

1 斐波那契数

# 1 子问题的重复计算
def fibonacci(n: int) -> int:"""使用递归方式计算第 n 个斐波那契数。该方法效率低,因为会重复计算相同的子问题。:param n: 要计算的斐波那契数的索引(从 1 开始):return: 返回第 n 个斐波那契数"""# 基础情况:第 1 个和第 2 个斐波那契数都是 1if n == 1 or n == 2:return 1else:# 递归调用:第 n 个斐波那契数等于前两个斐波那契数之和return fibonacci(n - 1) + fibonacci(n - 2)print(fibonacci(10))  # 使用递归方法,输出 55# 2 动态规划--》递推式
def fibonacci_no_recursion(n: int) -> int:"""使用迭代方式计算第 n 个斐波那契数,避免递归的重复计算。:param n: 要计算的斐波那契数的索引(从 1 开始):return: 返回第 n 个斐波那契数"""# 初始化斐波那契数列的前两个值f = [0, 1, 1]# 当 n 大于 2 时,通过迭代计算后续的斐波那契数if n > 2:for i in range(n - 2):# 计算下一个斐波那契数,并将其添加到列表中num = f[-1] + f[-2]f.append(num)# 返回第 n 个斐波那契数return f[n]print(fibonacci_no_recursion(100))  # 354224848179261915075

2 钢条切割问题

在这里插入图片描述
在这里插入图片描述

2.1 最优解情况

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 钢条切割问题之自定而下实现

import timedef cal_time(func):"""装饰器,用于计算函数的执行时间。:param func: 被装饰的函数:return: 包装后的函数,附加了执行时间的计算"""def wrapper(*args, **kwargs):# 记录开始时间t1 = time.time()# 执行被装饰的函数并获取返回值result = func(*args, **kwargs)# 记录结束时间t2 = time.time()# 计算并打印函数运行时间print(f"{func.__name__} running time: {t2 - t1} seconds.")# 返回函数执行的结果return resultreturn wrapperdef cut_rod_recurision_1(p: list, n: int) -> int:"""使用递归方法求解钢条切割问题。钢条切割问题的目标是将一根长度为 n 的钢条切成若干段,使得每段的总价值最大化。价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 如果钢条长度为 0,则最大收益为 0if n == 0:return 0# 初始化最大收益为切割长度为 n 的收益res = p[n]# 递归地计算所有可能的切割方式for i in range(1, n):# 对每个可能的切割点 i,计算最大收益res = max(res, cut_rod_recurision_1(p, i) + cut_rod_recurision_1(p, n - i))return res# price = [0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
# print(cut_rod_recurision_1(price, 9))  # 25def cut_rod_recurision_2(p: list, n: int) -> int:"""使用递归方法求解钢条切割问题的优化版本。该函数通过递归计算长度为 n 的钢条的最大收益。钢条的价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 如果钢条长度为 0,则最大收益为 0if n == 0:return 0# 初始化最大收益为 0,因为我们可能不切割钢条,即收益为 0res = 0# 递归地计算所有可能的切割方式for i in range(1, n + 1):# 对每个可能的切割点 i,计算当前切割方案的收益# res = max(当前最大收益, 将钢条切成长度 i 和 n-i 两部分的收益)res = max(res, p[i] + cut_rod_recurision_2(p, n - i))# 返回最大收益return res# price = [0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
# print(cut_rod_recurision_2(price, 9))  # 25price = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 28, 30, 33, 36, 37, 39, 40]
# print(len(price))
# print(cut_rod_recurision_2(price, 20))  # 56@cal_time
def c1(p: list, n: int) -> int:"""使用装饰器 cal_time 来计算并打印 cut_rod_recurision_1 函数的运行时间。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""return cut_rod_recurision_1(p, n)@cal_time
def c2(p: list, n: int) -> int:"""使用装饰器 cal_time 来计算并打印 cut_rod_recurision_2 函数的运行时间。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""return cut_rod_recurision_2(p, n)print(c1(price, 20))
print(c2(price, 20))

2.3 钢条切割问题之自底向上实现

在这里插入图片描述

import timedef cal_time(func):"""装饰器,用于计算函数的执行时间。:param func: 被装饰的函数:return: 包装后的函数,附加了执行时间的计算"""def wrapper(*args, **kwargs):# 记录开始时间t1 = time.time()# 执行被装饰的函数并获取返回值result = func(*args, **kwargs)# 记录结束时间t2 = time.time()# 计算并打印函数运行时间print(f"{func.__name__} running time: {t2 - t1} seconds.")# 返回函数执行的结果return resultreturn wrapperdef cut_rod_recurision_2(p: list, n: int) -> int:"""使用递归方法求解钢条切割问题的优化版本。该函数通过递归计算长度为 n 的钢条的最大收益。钢条的价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 如果钢条长度为 0,则最大收益为 0if n == 0:return 0# 初始化最大收益为 0,因为我们可能不切割钢条,即收益为 0res = 0# 递归地计算所有可能的切割方式for i in range(1, n + 1):# 对每个可能的切割点 i,计算当前切割方案的收益# res = max(当前最大收益, 将钢条切成长度 i 和 n-i 两部分的收益)res = max(res, p[i] + cut_rod_recurision_2(p, n - i))# 返回最大收益return resprice = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 28, 30, 33, 36, 37, 39, 40]@cal_time
def c2(p: list, n: int) -> int:"""使用装饰器 cal_time 来计算并打印 cut_rod_recurision_2 函数的运行时间。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""return cut_rod_recurision_2(p, n)@cal_time
def cut_rod_dp(p: list, n: int) -> int:"""钢条切割问题的动态规划解决方案,自底向上实现。该函数通过动态规划方法求解长度为 n 的钢条的最大收益。钢条的价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 初始化一个长度为 n+1 的列表 r,其中 r[i] 表示长度为 i 的钢条的最大收益r = [0] * (n + 1)# 遍历每一个可能的钢条长度 ifor i in range(1, n + 1):# 对于每个长度 i,初始化当前最大收益为 0res = 0# 遍历所有可能的切割点 j,从 1 到 ifor j in range(1, i + 1):# 计算切割方案的收益,并更新最大收益# res = max(当前最大收益, 切割成长度 j 和 i-j 两部分的收益)res = max(res, p[j] + r[i - j])# 将长度为 i 的钢条的最大收益存储在 r[i]r[i] = res# 返回长度为 n 的钢条的最大收益return r[n]print(cut_rod_dp(price, 15))  # 42

2.4 钢条切割问题-重构解-切割方案

在这里插入图片描述

import time
from typing import Tuple, Listdef cal_time(func):"""装饰器,用于计算函数的执行时间。:param func: 被装饰的函数:return: 包装后的函数,附加了执行时间的计算"""def wrapper(*args, **kwargs):# 记录开始时间t1 = time.time()# 执行被装饰的函数并获取返回值result = func(*args, **kwargs)# 记录结束时间t2 = time.time()# 计算并打印函数运行时间print(f"{func.__name__} running time: {t2 - t1} seconds.")# 返回函数执行的结果return resultreturn wrapperdef cut_rod_recurision_2(p: list, n: int) -> int:"""使用递归方法求解钢条切割问题的优化版本。该函数通过递归计算长度为 n 的钢条的最大收益。钢条的价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 如果钢条长度为 0,则最大收益为 0if n == 0:return 0# 初始化最大收益为 0,因为我们可能不切割钢条,即收益为 0res = 0# 递归地计算所有可能的切割方式for i in range(1, n + 1):# 对每个可能的切割点 i,计算当前切割方案的收益# res = max(当前最大收益, 将钢条切成长度 i 和 n-i 两部分的收益)res = max(res, p[i] + cut_rod_recurision_2(p, n - i))# 返回最大收益return res# price = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 28, 30, 33, 36, 37, 39, 40]@cal_time
def c2(p: list, n: int) -> int:"""使用装饰器 cal_time 来计算并打印 cut_rod_recurision_2 函数的运行时间。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""return cut_rod_recurision_2(p, n)@cal_time
def cut_rod_dp(p: list, n: int) -> int:"""钢条切割问题的动态规划解决方案,自底向上实现。该函数通过动态规划方法求解长度为 n 的钢条的最大收益。钢条的价格由列表 p 提供,其中 p[i] 表示长度为 i 的钢条的价格。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回长度为 n 的钢条的最大收益"""# 初始化一个长度为 n+1 的列表 r,其中 r[i] 表示长度为 i 的钢条的最大收益r = [0]  # 只包含一个元素 0,后续会扩展到长度为 n+1# 遍历每一个可能的钢条长度 i 从 1 到 nfor i in range(1, n + 1):# 对于每个长度 i,初始化当前最大收益为 0res = 0# 遍历所有可能的切割点 j,从 1 到 ifor j in range(1, i + 1):# 计算当前切割方案的收益,并更新最大收益# 比较当前最大收益和切割成长度 j 和 i-j 两部分的收益res = max(res, p[j] + r[i - j])# 将长度为 i 的钢条的最大收益存储在 r[i]r.append(res)# 返回长度为 n 的钢条的最大收益return r[n]# price = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 28, 30, 33, 36, 37, 39, 40]
# print(cut_rod_dp(price, 20))  # 56from typing import List, Tupledef cut_rod_extend(p: list, n: int) -> Tuple[int, List[int]]:"""扩展的钢条切割问题动态规划解决方案,自底向上实现。该函数不仅计算长度为 n 的钢条的最大收益,还追踪实现最大收益的切割方案。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回一个元组,其中第一个元素是长度为 n 的钢条的最大收益,第二个元素是一个列表,表示每个长度的钢条的最佳切割点"""# 初始化一个长度为 n+1 的列表 r,其中 r[i] 表示长度为 i 的钢条的最大收益r = [0] * (n + 1)# 初始化一个长度为 n+1 的列表 s,用于存储每个长度的钢条的最佳切割点s = [0] * (n + 1)# 遍历每一个可能的钢条长度 ifor i in range(1, n + 1):# 对于每个长度 i,初始化当前最大收益为 0res_r = 0  # 当前长度 i 的最大收益res_s = 0  # 对应最大收益的最佳切割长度# 遍历所有可能的切割点 j,从 1 到 ifor j in range(1, i + 1):# 比较通过切割长度 j 和 i-j 两部分的收益是否大于当前最大收益if p[j] + r[i - j] > res_r:# 更新最大收益和最佳切割长度res_r = p[j] + r[i - j]res_s = j# 将当前长度 i 的最大收益和最佳切割长度存储在 r 和 s 列表中r[i] = res_rs[i] = res_s# 返回长度为 n 的钢条的最大收益和最佳切割点列表return r[n], sdef cut_rod_solution(p: list, n: int) -> list:"""根据最佳切割点列表还原钢条切割方案该函数使用最佳切割点列表 `s` 还原出钢条的切割方案。:param p: 列表,包含各个长度的钢条对应的价格,p[0] 通常为 0:param n: 钢条的总长度:return: 返回一个列表,表示钢条的切割方案"""# 调用 cut_rod_extend 函数获取最佳切割点列表_, s = cut_rod_extend(p, n)ans = []  # 存储最终的切割方案while n > 0:# 将当前长度的最佳切割点添加到切割方案中ans.append(s[n])# 更新剩余长度n -= s[n]# 返回最终的切割方案return ansprice = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 28, 30, 33, 36, 37, 39, 40]
_, s = cut_rod_extend(price, 20)
print(s)  # [0, 1, 2, 3, 2, 2, 6, 1, 2, 3, 2, 2, 6, 1, 2, 3, 2, 2, 6, 1, 2]
print(cut_rod_extend(price, 20))  # (56, [0, 1, 2, 3, 2, 2, 6, 1, 2, 3, 2, 2, 6, 1, 2, 3, 2, 2, 6, 1, 2])
print(cut_rod_solution(price, 20))  # [2, 6, 6, 6]

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

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

相关文章

初识C语言指针(4)

目录 1. 字符指针变量 2. 数组指针变量 3. ⼆维数组传参的本质 4. 函数指针变量 5. typedef 关键字 6. 函数指针数组 结语 1. 字符指针变量 字符指针变量就是存储字符或字符串首字符地址的变量,字符指针变量有2种使用方式。 最常用的使用方式&#xff1a…

Datawhale X 李宏毅苹果书 AI夏令营(深度学习入门)task3

实践方法论 在应用机器学习算法时,实践方法论能够帮助我们更好地训练模型。如果在 Kaggle 上的结果不太好,虽然 Kaggle 上呈现的是测试数据的结果,但要先检查训练数据的损失。看看模型在训练数据上面,有没有学起来,再…

智能手机摄影综评:品牌联名与自建影像品牌的战略分析

随着智能手机摄影技术的飞速发展,各大厂商不仅与知名摄影品牌展开合作,还通过自建影像品牌来提升产品的摄影能力和品牌形象。本文将重点分析小米、华为、荣耀、OPPO、Vivo和苹果在摄影品牌联名与自建影像品牌方面的战略,探讨这些策略如何影响…

【案例55】WebSphere非root用户启动方案

问题背景 很多项目为了安全因素考虑,想让在Linux服务器中启动的程序都用非root用户启动。 解决方案 创建用户和组 现在我们用 root 用户登录,并创建用户和组。 ##创建用户 [rootnc-test ~]# useradd wasadmin##修改密码 [rootnc-test~]# passwd was…

Python优化算法16——鲸鱼优化算法(WOA)

科研里面优化算法都用的多,尤其是各种动物园里面的智能仿生优化算法,但是目前都是MATLAB的代码多,python几乎没有什么包,这次把优化算法系列的代码都从底层手写开始。 需要看以前的优化算法文章可以参考:Python优化算…

【学习笔记】技术分析-华为智驾控制器MDC Pro 610分析

华为的智能驾驶控制器一直在迭代,和网络上广泛披露的早期MDC 610相比,华为 MDC Pro 610 智能驾驶控制器,现在的样品设计采用了海思的双系统级芯片 (SoC) 提高了处理能力,三星的存储模块为无缝数据处理提供了充足的内存&#xff0c…

一分钟制作电子版的招生简章

​在当今信息化社会,快速、高效地传播信息显得尤为重要。招生简章作为学校、机构招生的重要宣传材料,其电子版制作更是需要简洁明了、吸引眼球。一分钟你就能制作出一份精美的电子版招生简章。让我们一起来看看,如何实现这一目标。 1.要制作电…

Linux 可视化管理工具:Webmin

😀前言 在 Linux 系统的运维管理中,命令行界面(CLI)是主要的操作方式。然而,对于许多系统管理员或开发者来说,使用 CLI 进行管理和维护任务并不总是最直观或最方便的方式。为了简化操作并提高效率&#xff…

今天你City了吗?维乐Angel Revo带你穿梭都市自由随风~

当7月的热浪在都市中翻滚,你是否渴望逃离钢筋水泥的束缚,寻找一片属于自己的绿意盎然?今天你City了吗?快带上VELO Angel Revo一起抓住夏日的尾巴,用一场骑行与这座城市的风景共舞!      轻巧出行&#…

面向对象编程:深入PHP的封装、继承和多态性!

文章目录 面向对象OOP的核心概念定义类、创建对象构造函数和析构函数访问修饰符继承方法重写接口和抽象类静态方法和属性魔术方法 错误处理错误处理概述错误级别异常处理自定义异常设置错误处理忽略错误错误日志断言 总结 面向对象编程(OOP)是一种编程范…

海绵城市雨水监测系统简介

海绵城市雨水监测系统主要有:数据采集、无线数据传输、后台云服务、终端平台显示等部分组成。系统通过前端数据采集水质(ss\cod\浊度、PH等)、雨水雨量、流量、水位、土壤湿度、气象等数据。通过无线数据传输通讯(4G、5G、以太网、…

洞见数据价值,激活组织活力,让决策更精准的智慧交通开源了。

智慧交通视觉监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上…

人工智能在专业领域的斗争

介绍 ChatGPT 等大型语言模型 (LLM) 在用自然语言讨论一般话题的能力方面令人印象深刻。然而,他们在医学、金融和法律等专业领域却举步维艰。这是由于缺乏真正的理解,并且注重模仿而不是智力。 大语言模型正处于炒作的顶峰。由于能够用自然语言回答和讨…

python库(20):Jsonschema库描述JSON数据的规范

1 Jsonschema简介 在当今信息时代,数据规范与交换变得越来越重要,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,被广泛应用于网络通信与前后端数据交互。 JSON Schema是一种用于描述JSON数据的规范…

力扣2025.分割数组的最多方案数

力扣2025.分割数组的最多方案数 哈希表 前缀和 用两个哈希表分别存元素(之后会遍历)左侧和右侧的前缀和 typedef long long LL;class Solution {public:int waysToPartition(vector<int>& nums, int k) {int n nums.size(),ans 0;vector<LL> sum(n);unor…

【Linux系列】SH 与 BASH 的区别:深入解析与使用案例

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

实现MySQL的主从复制基础

目录 1 MySQL实现主从复制的原理 1.1 实现主从复制的规则 1.2 如何实现主从复制 2 MySQL 实现主从复制实践 2.1 实验环境 2.2 my.cnf 配置添加 2.2.1 配置MSTER 端配置文件 2.2.2 配置SLAVE 端配置文件 2.2.3 三台MySQL服务器重启服务 2.3 创建用于复制的用户 2.4 保证三台主机…

51单片机——模块化编程

1、模块化编程介绍 传统方式编程&#xff1a;所有的函数均放在main.c里&#xff0c;若使用的模块比较多&#xff0c;则一个文件内会有很多的代码&#xff0c;不利于代码的组织和管理&#xff0c;而且很影响编程者的思路。 模块化编程&#xff1a;把各个模块的代码放在不同的.…

运维学习————nginx2-配置详解及负载均衡

目录 一、配置文件详解 1.1、结构 1.2、重要配置解释 1.3、详细配置 全局配置 Events HTTP 服务器配置 server虚拟主机配置 location URL匹配配置 1.4、完整配置 二、负载均衡 2.1、概念 2.2、集群规划及实现 2.3、具体实现 2.3.1、克隆 2.3.2、修改tomcat1配…

MySQL分区表

1.分区算法 MySQL提供4种分区算法&#xff1a;取余&#xff1a;Key&#xff0c;hash 条件&#xff1a;List&#xff0c;range 。 参与分区的参数字段需要为主键的一部分。 &#xff08;1&#xff09;KEY – 取余 &#xff0c;按照某个字段进行取余 分成5个区&#xff0c;就…