区间dp
例题:石子合并
设有
每堆石子有一定的质量,可以用一个整数来描述,现在要将这
每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。
例如有 1 3 5 2
, 我们可以先合并 4 5 2
, 又合并 9 2
,再合并得到
如果第二步是先合并 4 7
,最后一次合并代价为
问题是:找出一种合理的方法,使总的代价最小,输出最小代价。
输入格式
第一行一个数
第二行
输出格式
输出一个整数,表示最小代价。
数据范围
输入样例:
4
1 3 5 2
输出样例:
22
动态规划
分析:
每次合并只能合并相邻的石子,所以最后一次合并一定是左边连续的一部分和右边连续的一部分进行合并。
状态表示:
f[i][j]
表示将
状态计算:
-
时, ( 是前缀和数组, 是将左右两堆石子合并的代价) -
时, (合并一堆石子的代价为0)
#include <iostream>
using namespace std;
const int N = 310;
int s[N];
int f[N][N];
int main()
{
int n;
cin >>n;
for (int i=1;i<=n;i++) cin >>s[i], s[i] += s[i-1];
for (int len=2;len<=n;len++)
{
for (int i=1;i+len-1<=n;i++)
{
int j = i + len - 1;
f[i][j] = 1e9;
for (int k=i;k<j;k++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + s[j] - s[i-1]);
}
}
}
cout <<f[1][n];
}
原题链接:
区间dp常用模板
区间dp问题枚举时,第一维通常是枚举区间长度,并且一般
for (int len = 1; len <= n; len++) // 区间长度
{
for (int i = 1; i + len - 1 <= n; i++) // 枚举起点
{
int j = i + len - 1; // 区间终点
if (len == 1)
{
f[i][j] = 初始值;
continue;
}
for (int k = i; k < j; k++) // 枚举分割点,构造状态转移方程
{
f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + w[i][j]);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App