新闻中心
优化房屋花卉种植成本:基于动态规划的高效解决方案

本文旨在解决在N栋房屋中种植花卉的最小成本问题,其中每栋房屋可选择三种花色之一,且相邻房屋的花色不能相同。针对传统暴力枚举方案在N较大时效率低下、易导致内存溢出的问题,本文提出并详细阐述了基于动态规划的高效算法。通过定义状态、推导状态转移方程,并提供Python示例代码,演示了如何计算最小总成本以及如何重建最优花色选择路径,显著提升了算法性能。
问题概述
假设一条街上有N栋房屋,每栋房屋的庭院可以选择种植三种不同颜色的花卉(例如,白色、黄色、红色)中的一种。每种花色在每栋房屋都有对应的种植成本。核心约束是:任何两栋相邻房屋不能种植相同颜色的花卉。我们的目标是找到一种花卉种植方案,使得N栋房屋的总种植成本最低。
例如,对于四栋房屋,其花卉成本矩阵如下:
| 房屋/花色 | 白色 | 黄色 | 红色 |
|---|---|---|---|
| H1 | 5 | 6 | 7 |
| H2 | 3 | 7 | 9 |
| H3 | 6 | 7 | 3 |
| H4 | 1 | 8 | 4 |
一个可能的最低成本方案是:H1种植黄色 (6),H2种植白色 (3),H3种植红色 (3),H4种植白色 (1),总成本为 6 + 3 + 3 + 1 = 13。
低效解决方案的局限性
初学者可能会尝试使用暴力枚举法来解决此问题。一种常见的做法是利用itertools.product生成所有可能的颜色组合(例如,对于N栋房屋,每栋有3种颜色,则有$3^N$种组合),然后过滤掉所有相邻房屋颜色相同的无效组合,最后计算剩余有效组合的成本并找出最小值。
这种方法在N较小时尚可接受,但随着N的增大,组合数量呈指数级增长。当N超过20时,$3^{20}$是一个巨大的数字,生成和处理如此多的组合将导致:
- 时间复杂度过高:需要遍历所有组合,计算和过滤操作耗时巨大。
- 内存溢出:存储所有组合可能会迅速耗尽系统内存。
因此,对于大规模问题,我们需要一种更高效的算法。
动态规划方法
动态规划(Dynamic Programming, DP)是解决这类具有最优子结构和重叠子问题特性的优化问题的强大工具。本问题的核心思想是:要找到第i栋房屋的最优解,我们只需要知道第i-1栋房屋的最优解,并结合当前房屋的成本和约束条件。
1. 状态定义
我们可以定义三个变量来表示到当前房屋为止,以特定颜色结束的最小成本:
- cost_white: 表示到当前房屋为止,最后一栋房屋(即当前房屋)选择白色花卉时的最小总成本。
- cost_yellow: 表示到当前房屋为止,最后一栋房屋选择黄色花卉时的最小总成本。
- cost_red: 表示到当前房屋为止,最后一栋房屋选择红色花卉时的最小总成本。
2. 状态转移方程
对于每一栋房屋,我们根据前一栋房屋的最小成本来更新当前房屋的最小成本。
假设当前房屋的白色、黄色、红色花卉成本分别为x, y, z。
GemDesign
AI高保真原型设计工具
652
查看详情
- 选择白色 (x):如果当前房屋选择白色,则前一栋房屋不能是白色。因此,前一栋房屋的颜色只能是黄色或红色。我们选择这两种情况中成本较低的那个。 new_cost_white = x + min(prev_cost_yellow, prev_cost_red)
- 选择黄色 (y):如果当前房屋选择黄色,则前一栋房屋不能是黄色。因此,前一栋房屋的颜色只能是白色或红色。 new_cost_yellow = y + min(prev_cost_white, prev_cost_red)
- 选择红色 (z):如果当前房屋选择红色,则前一栋房屋不能是红色。因此,前一栋房屋的颜色只能是白色或黄色。 new_cost_red = z + min(prev_cost_white, prev_cost_yellow)
在每次迭代中,我们用new_cost_white, new_cost_yellow, new_cost_red来更新prev_cost_white, prev_cost_yellow, prev_cost_red,从而为下一栋房屋的计算做准备。
3. 初始状态
对于第一栋房屋,其成本就是选择相应花卉的成本。我们可以将prev_cost_white, prev_cost_yellow, prev_cost_red初始化为0,这样在处理第一行数据时,它们将分别加上第一行对应的花卉成本。
4. 最终结果
遍历完所有房屋后,cost_white, cost_yellow, cost_red将分别代表以白色、黄色、红色结束的最小总成本。取这三个值中的最小值,即为整个街区花卉种植的最低总成本。
示例代码:计算最小总成本
以下Python代码实现了上述动态规划逻辑,用于计算最小总成本:
def solve_min_cost(rows):
"""
计算在给定约束下,种植花卉的最小总成本。
Args:
rows: 一个列表的列表,其中每个子列表代表一栋房屋的三种花卉成本。
例如:[[5, 6, 7], [3, 7, 9], ...]
Returns:
int: 最小总成本。
"""
# 初始化,a, b, c 分别代表以颜色1, 2, 3结束的最小成本
# 初始值为0,在处理第一栋房屋时,会直接加上第一栋房屋的成本
cost_color1 = 0
cost_color2 = 0
cost_color3 = 0
for x, y, z in rows:
# 计算当前房屋选择颜色1时的最小成本
# 前一栋房屋不能选择颜色1,所以取颜色2或颜色3的最小成本
new_cost_color1 = min(cost_color2, cost_color3) + x
# 计算当前房屋选择颜色2时的最小成本
# 前一栋房屋不能选择颜色2,所以取颜色1或颜色3的最小成本
new_cost_color2 = min(cost_color1, cost_color3) + y
# 计算当前房屋选择颜色3时的最小成本
# 前一栋房屋不能选择颜色3,所以取颜色1或颜色2的最小成本
new_cost_color3 = min(cost_color1, cost_color2) + z
# 更新成本,为下一栋房屋的计算做准备
cost_color1, cost_color2, cost_color3 = new_cost_color1, new_cost_color2, new_cost_color3
# 所有房屋处理完毕后,取三种结束状态中的最小值
return min(cost_color1, cost_color2, cost_color3)
# 示例数据
rows = [
[5, 6, 7], # H1: white, yellow, red costs
[3, 7, 9], # H2: white, yellow, red costs
[6, 7, 3], # H3: white, yellow, red costs
[1, 8, 4] # H4: white, yellow, red costs
]
print(f"最小总成本: {solve_min_cost(rows)}") # 输出: 最小总成本: 13路径重建
仅仅知道最小总成本通常是不够的,我们还需要知道具体是哪些花色组合达到了这个最小成本。为了实现路径重建,我们需要在动态规划过程中额外存储选择信息。
1. 扩展状态定义
现在,我们的状态不仅仅是成本,还需要包含到达该成本的路径信息。我们可以将每个状态定义为一个元组 (cost, path_tuple),其中 cost 是最小成本,path_tuple 是一个表示路径的元组,它会指向前一个状态的路径。
- state_color1 = (cost_white, path_to_white)
- state_color2 = (cost_yellow, path_to_yellow)
- state_color3 = (cost_red, path_to_red)
2. 状态转移与路径记录
在计算 new_cost_colorX 时,我们不仅比较 prev_cost_colorY 和 prev_cost_colorZ,还要记录是哪一个导致了最小值。
例如,当计算 new_state_color1 时: min_prev_state = min(state_color2, state_color3) (这里 min 操作会比较元组的第一个元素,即成本) new_state_color1 = (min_prev_state[0] + x, (1, min_prev_state[1])) 其中 (1, min_prev_state[1]) 表示当前房屋选择了颜色1,并且其前一个状态的路径是 min_prev_state[1]。这里的 1 可以代表颜色索引(例如,1代表白色,2代表黄色,3代表红色)。
3. 路径回溯
当所有房屋处理完毕后,我们得到 state_color1, state_color2, state_color3。从中选择成本最低的那个作为最终状态 (final_cost, final_path_tuple)。然后,我们可以通过递归或循环的方式,沿着 final_path_tuple 中的链接回溯,逐层解构出完整的花色序列。由于路径是逆序存储的,最后需要将其反转。
示例代码:计算最小总成本及路径
def solve_min_cost_and_path(rows):
"""
计算在给定约束下,种植花卉的最小总成本,并返回具体的花色选择路径。
Args:
rows: 一个列表的列表,其中每个子列表代表一栋房屋的三种花卉成本。
Returns:
tuple: (int, list) 最小总成本和花色选择列表。
花色列表中的1, 2, 3分别代表三种颜色。
"""
# 初始化状态,每个状态包含 (成本, 路径)
# 路径使用元组链表表示,(当前颜色索引, 前一个路径元组)
# None 表示路径的起点
state_color1 = (0, None) # (cost, path_tuple)
state_color2 = (0, None)
state_color3 = (0, None)
# 辅助函数:扩展路径并更新成本
def extend_path(prev_state_a, prev_state_b, current_cost, color_index):
"""
根据前两种可能的结束状态和当前房屋的成本,计算新的状态。
"""
# 比较前两种状态的成本,选择更小的那个
sum_min_prev_state, path_min_prev_state = min(prev_state_a, prev_state_b)
# 返回新的状态:(新成本, 新路径)
# 新路径是 (当前颜色索引, 指向前一个最小路径的元组)
return sum_min_prev_state + current_cost, (color_index, path_min_prev_state)
for x, y, z in rows:
# 计算当前房屋选择颜色1, 2, 3时的状态
new_state_color1 = extend_path(state_color2, state_color3, x, 1)
new_state_color2 = extend_path(state_color1, state_color3, y, 2)
new_state_color3 = extend_path(state_color1, state_color2, z, 3)
# 更新状态
state_color1, state_color2, state_color3 = new_state_color1, new_state_color2, new_state_color3
# 所有房屋处理完毕后,选择成本最低的最终状态
min_sum, final_path_tuple = min(state_color1, state_color2, state_color3)
# 回溯重建路径
flat_path = []
current_path = final_path_tuple
while current_p
ath:
color_index, current_path = current_path # 解构 (当前颜色, 前一个路径)
flat_path.append(color_index)
# 由于路径是逆序构建的,需要反转
return min_sum, flat_path[::-1]
# 示例数据
rows = [
[5, 6, 7], # H1
[3, 7, 9], # H2
[6, 7, 3], # H3
[1, 8, 4] # H4
]
min_cost, path = solve_min_cost_and_path(rows)
print(f"最小总成本: {min_cost}") # 输出: 最小总成本: 13
print(f"最优花色路径: {path}") # 输出: 最优花色路径: [2, 1, 3, 1] (黄色, 白色, 红色, 白色)复杂度分析
- 时间复杂度: 算法遍历每栋房屋一次。对于每栋房屋,我们执行常数次(3次)的比较和加法操作。因此,如果N是房屋的数量,K是颜色的数量(这里K=3),时间复杂度为 $O(N \cdot K^2)$,简化为 $O(N)$。这比暴力枚举的 $O(K^N)$ 效率高得多。
-
空间复杂度:
- 仅计算最小成本时:我们只需要存储前一栋房屋的3个成本值,所以空间复杂度为 $O(K)$,简化为 $O(1)$。
- 同时重建路径时:每个状态需要存储路径信息,最坏情况下路径元组链表的深度为N。因此,总空间复杂度为 $O(N \cdot K)$,简化为 $O(N)$。
总结与注意事项
动态规划方法提供了一种高效且可扩展的解决方案,完美解决了暴力枚举在N较大时遇到的性能瓶颈。
-
优点:
- 效率高:时间复杂度为线性,能够处理大规模数据。
- 内存占用低:在仅计算成本时,空间复杂度为常数。
- 适用性:这种动态规划模式不仅适用于花卉种植问题,也广泛应用于其他具有类似“相邻元素约束”和“最小/最大化”目标的序列决策问题,例如房屋粉刷、旅行推销员问题的简化版本等。
- 扩展性:如果花色数量K发生变化,只需调整代码中处理K个状态的逻辑即可,算法的核心思想不变。
通过理解和应用动态规划,我们可以有效地解决许多复杂的优化问题,从而设计出高性能的算法。
以上就是优化房屋花卉种植成本:基于动态规划的高效解决方案的详细内容,更多请关注其它相关文章!
# 是一个
# 萝岗网站推广优化教程
# 鞍山网站怎么推广
# 临泉县网站seo优化外包公司
# 媒介营销推广模式有哪些
# 淘宝seo成功店铺
# 山西进口网络营销推广
# 网站付费推广方法
# 真人棋牌网站建设
# 温州网站软文推广
# 大型网站建设建站系统
# 只需
# 两种
# 最小值
# python
# 遍历
# 最优
# 三种
# 我们可以
# 递归
# 总成本
# red
# cos
# 内存占用
# 性能瓶颈
# 工具
# app
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
晋江读书网页版在线登录 晋江读书电脑版官网
微信商城在哪里打开【步骤】
Win11怎么修改默认浏览器_Windows 11设置Chrome为默认
AO3官方在线访问地址 Archive of Our Own最新镜像合集
Excel如何用迷你图显趋势_Excel用迷你图显趋势【趋势小图】
LINUX下如何进行磁盘分区_fdisk与parted工具在LINUX中的使用对比
PySpark中从现有列右侧提取可变长度字符创建新列的教程
QQ邮箱电脑版登录入口_QQ邮箱官方网站登录平台
MAC怎么安装Homebrew包管理器_MAC为开发者和高级用户安装命令行工具
iCloud登录入口网页版 苹果iCloud官网登录
Excel Power Pivot如何处理XML数据源 构建高级数据模型
深入理解Go语言中Map值与方法接收器的交互:为什么需要临时变量
Win11怎么关闭触摸屏_Windows 11禁用HID符合标准触摸屏
Eclipse怎么运行工程_Eclipse工程运行配置说明
C++如何检测键盘输入_C++ _kbhit与_getch函数非阻塞输入
J*aScript数据结构转换:将对象数组按类别分组
一加 14R 快充无反应_一加 14R 充电优化
一加手机拍照效果不好怎么办 一加哈苏影像调校与专业模式使用教程【高手篇】
照顾宝贝2小游戏点击立即在线玩
126邮箱网页版官方入口 126邮箱账号在线登录平台
C++ map遍历方法大全_C++ map迭代器使用总结
如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题
Pyrogram与g4f集成:异步编程实践与常见错误解决
谷歌浏览器如何快速清除某个网站的数据_Chrome网站缓存清理方法
单射、满射与双射的关系 一文理清所有逻辑
微信网页版官方入口教程 微信网页版网页版快速登录步骤
迅雷下载到U盘速度很慢怎么办_迅雷U盘下载慢优化方法
CSS Flexbox如何实现多行排列_flex-wrap wrap自动换行显示
Golang如何实现简单的Web表单_Golang表单提交与验证处理方法
汽水音乐车机版8.9下载 汽水音乐车机版8.9版本安装入口
J*aScript map 方法中处理循环元素为空数组的策略
PPT平滑切换怎么做 PPT炫酷“平滑”切换动画制作教程【必学】
怎么去除衣服上的口红印_生活小妙招教你用酒精轻松擦除
谷歌浏览器最新官方入口链接 谷歌浏览器网页版官网导航
虚幻5科幻题材ARPG大作遭取消!本是《奇异人生》厂商新作
React Hooks最佳实践:动态组件状态管理的组件化方案
学习通网页版官方登录 超星学习通电脑端入口指南
如何使用Go和Martini动态服务解码后的图片
HuggingFaceEmbeddings中向量嵌入维度调整的限制与理解
QQ邮箱网页版入口页面 QQ邮箱在线登录入口官网
妖精动漫免费平台 妖精动漫官网资源观看网址
uc浏览器网页版入口 uc浏览器网页版最新网址
企业名称高精度匹配:N-gram方法在结构相似性分析中的应用
VS Code远程开发时如何处理文件权限问题
优化LangChain文档加载与ChromaDB集成:解决多文档处理与分块问题
不同用户不同价格! 索尼开启账户个性化定价测试
FullCalendar 自定义按钮样式定制指南
批改网学生版PC登录 批改网官网登录系统入口
Golang如何使用context实现超时取消_Golang context超时取消模式实践
在J*a中如何开发简易电子商务商品管理系统_商品管理系统项目实战解析


2025-12-09
浏览次数:次
返回列表
ath:
color_index, current_path = current_path # 解构 (当前颜色, 前一个路径)
flat_path.append(color_index)
# 由于路径是逆序构建的,需要反转
return min_sum, flat_path[::-1]
# 示例数据
rows = [
[5, 6, 7], # H1
[3, 7, 9], # H2
[6, 7, 3], # H3
[1, 8, 4] # H4
]
min_cost, path = solve_min_cost_and_path(rows)
print(f"最小总成本: {min_cost}") # 输出: 最小总成本: 13
print(f"最优花色路径: {path}") # 输出: 最优花色路径: [2, 1, 3, 1] (黄色, 白色, 红色, 白色)