Description
设有 N(N≤300) 堆石子排成一排,其编号为1,2,3,⋯,N。每堆石子有一定的质量 mi(mi≤1000)。 现在要将这N堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻。 合并时由于选择的顺序不同,合并的总代价也不相同。试找出一种合理的方法,使总的代价最小,并输出最小代价。
输入格式
第一行,一个整数 N。 第二行,N 个整数 mi。
输出格式
输出仅一个整数,也就是最小代价。(题目确保答案在int范围)
输入样例
4 2 5 3 1
输出样例
22
解析:重点在于设置分割点,代表了不同的合并决策,大小为l<k<r。起点l总是从1开始,r为l+枚举区间长度-1.最后输出f[1][n].
#include <iostream>
#include <cstring>
#include <math.h>
#include <algorithm>
using namespace std;
const int N=100;
int a[N];//每个石子的重量
int s[N];石子重量前缀和
int f[N][N];合并代价
int main()
{
int n;
cin>>n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
f[i][i]=0;
}
int len=0;
//区间动态规划
//将区间划分为大小为len的枚举区间长度
for(len=2;len<=n;len++){
//设置起点
for(int l=1;l+len-1<=n;l++){
//设置终点
int r=l+len-1;
//在区间内设置分割点,方便进行动态代价计算
for(int k=l;k<r;k++){
//合并石子的代价就是分割点左边一堆合并代价+右边一堆合并代价+最后合并起来的值
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
}
}
}
cout << f[1][n] << endl;
return 0;
}