题目
Description
设有 N(N≤300) 堆石子排成一排,其编号为1,2,3,⋯,N。每堆石子有一定的质量 mi(mi≤1000)。
现在要将这N堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻。
合并时由于选择的顺序不同,合并的总代价也不相同。试找出一种合理的方法,使总的代价最小,并输出最小代价。
输入格式
第一行,一个整数 N。
第二行,N 个整数 mi。
输出格式
输出仅一个整数,也就是最小代价。(题目确保答案在int范围)
输入样例
4
2 5 3 1
输出样例
22
提示
区间动态规划。题解可参考 11078 不能移动的石子合并(优先做)
题解
代码
#include <iostream>
using namespace std;
const int N = 310;
int s[N], dp[N][N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> s[i];
s[i] += s[i-1];
}
// 枚举区间长度,区间长度从2开始,至少得有2堆才能合并
// 当起点为1时,区间长度至多为n,至多n个元素
for(int len = 2; len <= n; len++)
for(int i = 1; i + len - 1 <= n; i++){//枚举区间起点
int j = i + len - 1;//区间右边界
dp[i][j] = 1e8;//初始化合并区间i~j的最小代价为无穷大
for(int k = i; k <= j-1; k++)//枚举划分边界,即合并的第一堆的右边界
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + s[j] - s[i-1]);//求合并区间i~j的最小代价,为dp[i][k] + dp[k+1][j] + s[j]-s[i-1]
}
cout << dp[1][n] << endl;
return 0;
}