news 2026/3/19 6:19:04

石子合并模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
石子合并模型

经典问题描述:

有 n 堆石子排成一排,第 i 堆有 ai 个石子。
每次只能合并相邻的两堆,合并代价等于这两堆石子的总数。
合并后形成一堆新石子。
问:把所有石子合并成一堆的最小总代价

输入

3(n的大小)

8 5 8

输出

34

解释:首先合并8-5成13,代价是13. 合并后石子为13 8.然后合并13-8,代价是21.所以总代价为34

贪心or动态规划

在石子合并里,最自然的贪心直觉只有这一种:

每一步都合并当前代价最小的相邻两堆

也就是:每次找 a[i] + a[i+1] 最小的一对,先合它

这个策略非常“像 Huffman”,所以特别容易误入。

⚠️ 问题就出在:
石子合并中,一次合并的结果,会被“反复收费”

所以当前的最小代码,并不是全局的最小代价。这就是贪心失效的根本原因

贪心反例

石子堆: 4 3 3 4
贪心做法(每次合最小相邻对)

1️⃣ 合并中间的3 + 3 = 6
代价 = 6
现在变成:4 6 4
2️⃣ 合并4 + 6 = 10(或 6+4)
代价 = 10

现在变成:10 4

3️⃣ 合并10 + 4 = 14
代价 = 14

📌 总代价:6 + 10 + 14 = 30

最优做法(非贪心)

1️⃣ 先合左边4 + 3 = 7
代价 = 7

7 3 4

2️⃣ 再合右边3 + 4 = 7
代价 = 7

7 7
3️⃣ 最后合并7 + 7 = 14
代价 = 14

📌 总代价:7 + 7 + 14 = 28

这是一个「区间 DP」问题

记住一句判断口诀

“对象是连续区间,决策是选断点,代价和区间整体有关”
→ 基本就是区间 DP

我们逐条对照石子合并:

状态的本质是什么?

最终不是关心“某一步怎么合”,
而是关心:

某一段连续石子合并成一堆,最少要花多少钱

这句话本身就已经是一个区间:[l ........ r]

所以状态一定是:dp[l][r] = 把第 l 堆到第 r 堆合并成一堆的最小代价

⚠️ 注意:

  • 不是过程

  • 是“已经合并完成”的最优结果

状态转移是怎么发生的

不管你前面怎么合:

  • 最后一步

  • 一定是把某两堆「已经合并好的大堆」合成一堆

  • 而这两堆必然形如:

    [l .... k] + [k+1 .... r]

    [l..k][k+1..r]各自已经合成一堆;合并它们的代价 =区间总石子数

设前缀和:sum[i] = a1 + a2 + ... + ai
那么:cost(l, r) = sum[r] - sum[l-1]

所以状态转移就只能是:

dp[l][r] = min over k∈[l, r-1] ( dp[l][k] + dp[k+1][r] + cost(l, r) )

边界条件

一个堆需要合并吗?

dp[i][i] = 0

不需要任何代价

C++代码实现

int sum(int prefix[], int l, int r) { return prefix[r] - prefix[l - 1]; } int main() { int n; cin >> n; int a[107], prefix[107] = { 0 }; //我这里下标是从1开始的 for (int i = 1; i <= n; i++) { cin >> a[i]; } //prefix[i]是从[1,i]的和 for (int i = 1; i <= n; i++) { prefix[i] = prefix[i - 1] + a[i]; } //dp表示把区间 [l, r] 合并成一堆的最小代价 long long dp[107][107]; //单根不用合并 for (int i = 1; i <= n; i++) dp[i][i] = 0; //枚举合并区间长度 for (int len = 2; len <= n; len++) { //枚举开始位置 for (int l = 1; l + len - 1 <= n; l++) { //区间是[l,l+len-1],长度就是len int r = l + len - 1; dp[l][r] = LLONG_MAX; //所谓合并,可以这么理解 //如果[l,k]和[k+1,r]已经合并完了,那么再合并的代价就是sum(l,k)+sum(k+1,r)即sum(l,r) //然后[l,k]和[k+1,r]也有合并的代价,所以[l,k]和[k+1,r]的合并代价就是dp[l][k]+dp[k+1][r]+sum(l,r) //我们枚举所有k属于[l,r),这样就能找到dp[l][r]的最小合并代价 for (int k = l; k < r; k++) { dp[l][r] = fmin(dp[l][r], dp[l][k]+dp[k+1][r]+sum(prefix,l,r)); } } } cout << dp[1][n]; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/14 14:19:38

Java对接PLC与SCADA系统的逻辑中枢设计(工业4.0核心技术解密)

第一章&#xff1a;Java对接PLC与SCADA系统的意义与挑战在工业自动化系统中&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;和监控与数据采集系统&#xff08;SCADA&#xff09;承担着核心的数据采集与控制任务。随着企业对生产过程可视化、远程监控及系统集成需求的…

作者头像 李华
网站建设 2026/3/14 10:47:23

JupyterHub企业级部署完整指南:从零搭建到生产级运维

JupyterHub作为多用户Jupyter notebook服务器&#xff0c;已经成为企业数据科学团队协作的首选平台。本指南将带您从基础环境准备到生产级部署&#xff0c;全面掌握JupyterHub的企业级应用技巧&#xff0c;帮助您快速搭建稳定可靠的数据科学协作环境。 【免费下载链接】jupyter…

作者头像 李华
网站建设 2026/3/17 10:56:58

Gumbo HTML5解析器深度实践:从入门到项目集成的完整指南

Gumbo是一款纯C99语言实现的HTML5解析器&#xff0c;专为构建高质量网页分析工具和库而设计。作为开发者&#xff0c;掌握这个轻量级但功能强大的解析器将为您的项目带来显著的效率提升。本文将从基础概念到高级应用&#xff0c;为您提供全面的技术指导。 【免费下载链接】gumb…

作者头像 李华
网站建设 2026/3/10 19:32:45

mybatisplus在管理lora-scripts训练任务后台系统中的集成思路

MyBatis-Plus 在 LoRA 训练任务管理系统中的集成实践 在当前 AIGC 技术迅猛发展的背景下&#xff0c;LoRA&#xff08;Low-Rank Adaptation&#xff09;作为一种轻量级模型微调方法&#xff0c;因其对计算资源要求低、适配速度快&#xff0c;已被广泛应用于 Stable Diffusion 图…

作者头像 李华
网站建设 2026/3/11 14:19:00

Tome深度评测:这款MCP客户端如何让AI文档创作效率提升3倍?

Tome深度评测&#xff1a;这款MCP客户端如何让AI文档创作效率提升3倍&#xff1f; 【免费下载链接】awesome-mcp-clients A collection of MCP clients. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-mcp-clients 在AI工具快速迭代的今天&#xff0c;MCP&…

作者头像 李华
网站建设 2026/3/16 23:29:18

10分钟搞定Kubernetes测试环境:kubeasz AllinOne极速部署指南

10分钟搞定Kubernetes测试环境&#xff1a;kubeasz AllinOne极速部署指南 【免费下载链接】kubeasz 一款基于Ansible的Kubernetes安装与运维管理工具&#xff0c;提供自动化部署、集群管理、配置管理等功能。 - 功能&#xff1a;提供自动化部署Kubernetes集群、节点管理、容器管…

作者头像 李华