区间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;
}
相关推荐
程序员阿鹏4 分钟前
为什么MySQL InnoDB选择B+树?
数据结构·数据库·b树·sql·mysql·算法·缓存
AI 思录26 分钟前
Prompt 事故档案(八):日常表达被标为“待校准”,AI 的爹味语法从哪里来
大数据·人工智能·算法·prompt·用户体验·ai合规
月光船幽幽31 分钟前
跨范式映射的稳定接口设计
人工智能·python·算法
2601_965742222 小时前
全媒体运营与短视频代运营,两者有什么区别?
大数据·数据结构·人工智能·算法·ai·媒体
wordbaby3 小时前
混合检索:两全其美的艺术
人工智能·算法
彧azz3 小时前
数据结构:关于图的学习
c语言·数据结构·笔记·学习·算法
热心网友俣先生3 小时前
A题-药材的烘干问题-题意逐句翻译
算法·数学建模
2601_960356383 小时前
2026秋招运营分析师能力模型:SQL、指标体系、AIGC与业务分析
算法
hetao17338373 小时前
校内场-提高组 ZYZSC-S-Round 4
c++·算法
彧azz4 小时前
二叉搜索树学习记录
c语言·数据结构·笔记·算法