石子合并三大题型
- 任意两堆石子合并,直接手写一个小根堆,每次取前面两个相加,得到的值继续放入优先队列中,直到里面只有一个元素就输出
- 只能合并相邻两堆石子,这就类似于矩阵连乘(传送门),不过还是有一些差别
- 在2的基础上,这些石子形成一个环形,这又是一种新的题型
今天记录的是第二种——区间dp
题目描述
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】
输入
本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。
输出
输出最小花费。
样例输入
5
1 2 3 4 5
样例输出
33
ps:
首先分析一下这个题目,举个例子,如果只有三堆 4 , 5 , 9
我们合并这三堆所花费的来自三部分
- 第一二堆合并的花费
- 第一二堆石子的个数和
- 第三堆石子的数量
- 那么就是4+5+9+6=24
但是这个题目要求的是相邻两堆之间合并,如果又很多堆石子,那么我们就要去找断点,最优值问题就是一个个最优子结构,所以我们需要一个一个去找断点,算出每一个最优子结构,然后相加
转移方程如下
此外我们需要引入一个数组,来记录石子的数量,可以利用前缀和思想,也可以直接存储第i到第j石子的数量
前缀优化
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3 + 5;
int a[maxn], b[maxn], dp[maxn][maxn];
int main()
{
int n;
while (~scanf("%d", &n))
{
memset(dp, <