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

news/2024/9/18 12:20:03/ 标签: 算法, 动态规划, 代理模式

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.ppmy.cn/news/1516451.html

相关文章

美国高防服务器测评

美国高防服务器通常具有出色的硬件配置和网络性能,以及强大的DDoS防御能力。rak小编为您整理发布美国高防服务器测评。 美国高防服务器因其地理位置和网络基础设施的优势,通常被认为在防御分布式拒绝服务(DDoS)攻击方面具有较高的能力。面对日益增长的网…

基于R语言遥感随机森林建模与空间预测

随机森林作为一种集成学习方法,在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性,随机森林在降低模型方差和过拟合风险方面具有显著优势。在训练过程中,使用Bootstrap抽样生成不同的训练集&#xff…

力扣: 两两交换链表中的节点

文章目录 需求代码代码解释结尾 需求 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 输入:…

工厂模式与策略模式:理解与应用

工厂模式与策略模式:理解与应用 1. 引言2. 工厂模式简介2.1 定义2.2 特点2.3 应用场景2.4 工厂模式例子:咖啡制作 3. 策略模式简介3.1 定义3.2 特点3.3 应用场景3.4 策略模式例子:咖啡定价 4. 区别4.1 目的不同4.2 应用场景不同4.3 解决问题不…

浅谈Java Maven

一、基本介绍 Maven是Java项目的构建工具,通过项目对象模型(POM)管理项目配置信息,自动化构建、测试和部署过程。开发人员可定义项目结构、依赖和构建流程,提高开发效率和质量。本文介绍基本概念和用法,帮助…

【YOLOv8改进[Conv]】 感受野注意力卷积RFAConv(2024.3)| 使用RFAConv改进目标检测效果 + 含全部代码和详细修改方式

本文将进行在YOLOv8中使用 感受野注意力卷积RFAConv改进v8 的实践,助力YOLOv8目标检测效果,文中含全部代码、详细修改方式。助您轻松理解改进的方法。

时尚图像编辑

时尚图像编辑是一种应用计算机视觉和机器学习技术来改变或增强时尚摄影图像的领域。这种编辑可以包括更改服装颜色、形状或整体风格,以及调整模特在图像中的姿态或场景背景。 在您提到的背景中,现有的时尚图像编辑方法依赖于如分割器和关键点提取器这样…

FreeRTOS学习笔记>中断管理

1. 异常的定义与分类 异常:是指任何导致处理器脱离正常执行路径、并转向执行特定代码的事件。异常如果不及时处理,可能导致系统错误甚至瘫痪,因此异常处理对于系统的稳定性和鲁棒性非常重要,特别是在实时系统中。异常分类&#x…

【markdown 中的文字颜色设置】按色系分类

文本颜色分类 蓝绿色系:灰色系:蓝紫色系:粉色系:绿色系:橘棕色系:语法,以天蓝色为例: <font color=skyblue>我是文字</font>我是文字 或者 替换成对应的16进制 <font color=#87CEEB>同理</font>同理 接下来是按色系分类的颜色名 蓝绿色系: …

速盾:前端cdn加速是什么意思?

前端CDN加速是指通过使用内容分发网络&#xff08;CDN&#xff09;来加速前端页面加载和内容访问的一种技术手段。CDN是一种分布式架构的网络&#xff0c;通过将内容缓存到离用户更近的服务器节点上&#xff0c;可以有效地减少网络延迟&#xff0c;并提高页面加载速度和用户体验…

Golang测试func TestXX(t *testing.T)的使用

一般Golang中的测试代码都以xxx_test.go的样式&#xff0c;在命名测试函数的时候以Testxx开头。 以下是我写的一个单元&#xff1a; package testsimport "strings"func Split(s, sep string) (res []string) {i : strings.Index(s, sep)for i > -1 {res append…

ASAM OpenX系列标准

ASAM OpenX系列标准是由德国自动化及测量系统标准协会&#xff08;ASAM&#xff09;制定的一系列标准&#xff0c;旨在推动自动驾驶仿真测试领域的发展。该系列标准涵盖了仿真测试场景的不同方面&#xff0c;为自动驾驶技术的研发、测试和验证提供了统一的规范和框架。以下是对…

Dopamine(多巴胺)越狱工具一键越狱教程:支持 iOS 15-iOS 16.6.1 设备

Dopamine&#xff08;多巴胺&#xff09;越狱工具由巨魔商店 TrollStore 的作者 opa334 联合 ellekit 开发&#xff0c;是公开的一个开源越狱工具&#xff0c;面向所有人员使用。用户可通过爱思助手“一键越狱”安装此工具进行越狱&#xff0c;操作更加便捷&#xff0c;以下是相…

ffmpeg教程及加速视频转码

ffmpeg教程及加速视频转码 1、ffmpeg简介&#xff1a; ffmpeg来自MPEG视频编码标准。 是一套可以用来记录&#xff0c;转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。 可以轻易的实现多种视频格式之间的相互转换。 2、基础知识&#xff1a; 容器、文件…

ZooKeeper--基于Kubernetes部署ZooKeeper

ZooKeeper 服务 服务类型: 无头服务&#xff08;clusterIP: None&#xff09;&#xff0c;这是 StatefulSet&#xff08;有状态集&#xff09;必需的配置。 端口: 2181 (客户端): 用于客户端连接。 2888 (跟随者): 用于 ZooKeeper 服务器之间的连接。 3888 (领导者): 用于领导者…

多平台谷歌浏览器驱动下载地址分享

多平台谷歌浏览器驱动下载地址分享 一、概述二、windows、linux、mac平台下载地址2.1windows平台下载地址2.2linux、mac平台下载地址 三、arm平台下载地址参考文档 一、概述 在使用一些自动化网页测试工具时&#xff0c;往往需要下载谷歌浏览器驱动文件&#xff0c;用于配合工…

虚幻5|按键触发学习

一&#xff0c;如图参考 1.下移 驱动阈值 越大按时间长才会触发&#xff0c;越小很快就可以触发 2.按下 当按下超出驱动阈值大小就会触发一次&#xff0c;这里的驱动阈值只能设置再0.1~1的大小 3.已松开 当按下的时候&#xff0c;先触发单次的started&#xff0c;如果按压…

[多线程] linux中的线程调度策略

文章目录 多线程调度如何设置调度策略Reference 多线程调度 包含5种线程调度&#xff1a; SCHED_OTHER&#xff1a;SCHED_FIFO&#xff1a;SCHED_RR&#xff1a;SCHED_BATCH&#xff1a;SCHED_IDLE&#xff1a; 如何设置调度策略 在Linux系统中&#xff0c;线程调度策略可以…

分组汇总后再根据数量拼上不同文字

Excel某表格有2列。 AB1Apples32Apples03Bananas14Bananas65Cantaloupe06Kiwis27Kiwis28Kiwis1 要求&#xff1a;按第1列分组&#xff0c;如果组内第2列大于0则对当前行进行计数&#xff0c;否则不计数&#xff1b;计数结果等于1则附加Occurrence&#xff0c;否则附加 Occurr…

一个php快速项目搭建框架源码,带一键CURD等功能

介绍&#xff1a; 框架易于功能扩展&#xff0c;代码维护&#xff0c;方便二次开发&#xff0c;帮助开发者简单高效降低二次开发成本&#xff0c;满足专注业务深度开发的需求。 百度网盘下载 图片&#xff1a;