区间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;
}
相关推荐
吞下星星的少年·-·1 小时前
线段树模板
算法
段一凡-华北理工大学2 小时前
2026 高炉炼铁智能化技术全景与演进路径~系列文章11:演进路径与行业未来
大数据·网络·人工智能·算法·工业智能体·高炉炼铁智能化
叶小鸡2 小时前
小鸡玩算法-力扣HOT100-多维动态规划
算法·leetcode·动态规划
星马梦缘2 小时前
aaaaa
数据结构·c++·算法
菜菜的顾清寒3 小时前
力扣HOT100(42)链表-随机链表的复制
算法·leetcode·链表
lqqjuly3 小时前
模型剪枝与稀疏化:理论、算法与可运行实现
人工智能·算法·剪枝
逻辑君4 小时前
Foresight研究报告【20260011】
人工智能·线性代数·算法·矩阵
珊瑚里的鱼4 小时前
【动态规划】不同路径Ⅱ
算法·动态规划
适应规律4 小时前
【无标题】
人工智能·python·算法