问题描述
在一条直线上有 n 堆石子,每堆有一定的数量。
每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。
求把所有石子合并成一堆的最小花费。
输入格式
输入第一行包含一个整数 n,表示石子的堆数。
接下来一行,包含 n 个整数,按顺序给出每堆石子的大小 。
输出格式
输出一个整数,表示合并的最小花费。
样例输入
5
1 2 3 4 5
样例输出
33
数据范围
1 ≤ n ≤ 1000, 每堆石子至少1颗,最多10000颗。
题解
动态规划:
f[l][r]
:
集合
:所有将第 L 堆石子 ~ 第 R 堆石子合并成一堆石子的方案的集合。属性
:最小值
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1010;
int w[N], f[N][N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++)
{
cin >> w[i];
w[i] += w[i - 1]; // 前缀和
}
memset(f, 0x3f, sizeof f);
for (int len = 1; len <= n; len ++) // 枚举区间长度
for (int l = 1; l + len - 1 <= n; l ++) // 枚举左端点
{
int r = l + len - 1; // 对应的右端点
if(len == 1) f[l][r] = 0; // 一堆石子不损耗体力
else
{
for (int k = l; k < r; k ++) // 枚举区间断点
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + w[r] - w[l - 1]);
}
}
cout << f[1][n] << endl;
return 0;
}