区间dp-基础题目1(石子合并)

题目链接

解题思路

我们把合并 1 至 n 1至n 1至n堆石子拆解成一个个子问题:

因为合并相邻两堆石子的值我们是可以确定的,已知任意两堆相邻的石子合并的代价之后,对于三堆石子,我们可以考虑两种方法

  • 先合并 1 至 2 1至2 1至2堆,再把前 2 2 2堆和第 3 3 3堆石子合并。
  • 先合并 2 至 3 2至3 2至3堆,再把后 2 2 2堆和第 1 1 1堆石子合并。

对于题目样例,4堆石子,代价分别为4,5,9,4。

①先考虑合并两堆石子的情况

合并区间 1,2 2,3 3,4
代价 9 14 13

②考虑合并三堆石子的情况:

1)前三堆石子合并,如果先合并 1 至 2 1至2 1至2堆,再把前 2 2 2堆和第 3 3 3堆石子合并,代价为 9 + 4 + 5 + 9 = 27 9+4+5+9=27 9+4+5+9=27;如果先合并 2 至 3 2至3 2至3堆,再把后 2 2 2堆和第 1 1 1堆石子合并,代价为 9 + 5 + 4 + 5 + 9 = 32 9+5+4+5+9=32 9+5+4+5+9=32。取较小值,27。

2)后三堆石子合并,如果先合并 2 至 3 2至3 2至3堆,再把 2 至 3 2至3 2至3堆和第 4 4 4堆石子合并,代价为 5 + 9 + 5 + 9 + 4 = 32 5+9+5+9+4=32 5+9+5+9+4=32;如果先合并 3 至 4 3至4 3至4堆,再把 3 至 4 3至4 3至4堆和第 2 2 2堆石子合并,代价为 9 + 4 + 5 + 9 + 4 = 31 9+4+5+9+4=31 9+4+5+9+4=31。取较小值,31。

③考虑合并四堆石子的情况:

1)前三堆石子和第四堆石子合并,根据②,前三堆石子合并的最小代价为27,再和第四堆石子合并,代价为 27 + 4 + 5 + 9 + 4 = 49 27+4+5+9+4=49 27+4+5+9+4=49。

2)前两堆石子和后两堆石子合并,根据①,前两堆石子合并的最小代价为9,后两堆石子合并的最小代价为13,前两堆石子和后两堆石子合并的代价为 9 + 13 + 4 + 5 + 9 + 4 = 44 9+13+4+5+9+4=44 9+13+4+5+9+4=44。

3)第一堆石子和后三堆石子合并,根据②,后三堆石子合并的最小代价为31,一堆石子和后三堆石子合并的最小代价为 31 + 4 + 5 + 9 + 4 = 53 31+4+5+9+4=53 31+4+5+9+4=53。

实现算法

前面的样例模拟过程可以总结以下过程:

  • 我们设 d p l r dplr dplr为合并区间 l , r l,r l,r内的石子的最小代价。 d p dp dp数组初始化为0。
  • 我们通过前面的分析知道,合并区间 l , r l,r l,r内的石子的最小代价, d p l r = m i n ( d l k + d p k + 1 r ) + 区间 l , r 内所有石子的重量 ( l < = k < r ) dplr=min(dlk+dpk+1r)+区间l,r内所有石子的重量(l<=k<r) dplr=min(dlk+dpk+1r)+区间l,r内所有石子的重量(l<=k<r)。区间内石子的重量,我们实际上可以做一个计算前缀和的预处理,前缀和结果存储在数组 s s s中,这样查询区间 l , r l,r l,r内所有石子的重量就更高效了。
  • 做完准备工作后,执行以下过程:
    1)我们从2开始枚举所有可能的长度 l n ln ln;
    2)在枚举长度的循环内,枚举区间的左右端点 l l l和 r r r, l l l从1开始枚举, r r r从 l + l n − 1 l+ln-1 l+ln−1开始枚举,结束条件是 r < = n r<=n r<=n;
    3)在枚举区间左右端点的循环内,我们还有枚举断点 k ( l < = k < r ) k(l<=k<r) k(l<=k<r),枚举 k k k的循环中执行状态转移方程: d p l r = m i n ( d p l r , d p l k + d p k + 1 r + s r − s l − 1 ) dplr=min(dplr,dplk+dpk+1r+sr-sl-1) dplr=min(dplr,dplk+dpk+1r+sr−sl−1)。
    4)最后输出答案: d p 1 n dp1n dp1n

AC代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m[1005], s[1005], dp[1005][1005];
signed main() {
	cin >> n;
	memset(dp, 0x3f, sizeof(dp));
	for (int i = 1; i <= n; i++) {
		cin >> m[i];
		s[i] = s[i - 1] + m[i];
		dp[i][i] = 0;
	}
	for (int ln = 2; ln <= n; ln++) {
		for (int l = 1, r = l + ln - 1; r <= n; l++, r++) {
			for (int k = l; k < r; k++) {
				dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r] + s[r] - s[l - 1]);
			}
		}
	}
	cout << dp[1][n];
	return 0;
}
相关推荐
ysa0510302 分钟前
【板子】树上启发式合并
数据结构·c++·笔记·算法
学究天人20 分钟前
数学公理体系大全:第一章 命题逻辑:真值之舞
人工智能·算法·机器学习·数学建模·动态规划·图论·抽象代数
小O的算法实验室21 分钟前
2025年Neurocomputing,基于LLM的进化优化器:结合精英策略推理
算法
2301_800256111 小时前
数据结构基础期末复习例题
数据结构·算法
变量未定义~2 小时前
单调栈-四元组问题
数据结构·算法
冷小鱼2 小时前
AI Agent 核心算法:任务规划(Planning)的深度技术解析
人工智能·算法·planning
退休倒计时2 小时前
【每日一题】LeetCode 78. 子集 TypeScript
算法·leetcode·typescript
旖-旎2 小时前
《LeetCode 978 最长湍流子数组 || LeetCode 139 单词拆分》
c++·算法·leetcode·动态规划
cxr8282 小时前
第16章 跨域迁移与能力融合——从专家到通才
人工智能·算法·智能体·hermes
学究天人3 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(补充卷9)
人工智能·线性代数·算法·数学建模·动态规划·原型模式·抽象代数