设有n堆石子排成一排,其编号为1,2,3,…,n。每堆石子有一定的数量,例如: 13 7 8 16 21 4 18 现要将n堆石子归并为一堆。归并的过程为每次只能将相邻的两堆石子堆成一堆,这样经过n-1次归并之后最后成为一堆。对于上面的7堆石子,可以有多种方法归并成一堆。其中的2种方法入下图:
归并的代价是这样定义的:将两堆石子归并为一堆时,两堆石子数量的和称为归并2堆石子的代价。如上图中,将13和7归并为一堆的代价为20。归并的总代价指的是将沙子全部归并为一堆沙子的代价的和。如上面的2种归并方法中, 第1种的总代价为 20+24+25+44+69+87 = 267 第2种的总代价为 15+37+22+28+59+87 = 248 由此可见,不同归并过程得到的总的归并代价是不一样的。 当n堆石子的数量给出后,找出一种合理的归并方法,使总的归并代价为最小。
输入
第1行:1个整数n(1<=n<=100),表示石子的数量第
2行:n个用空格分开的整数,每个整数均小于10000,表示各堆石子的数量。
输出
1个整数,表示最小的归并代价
样例输入
3
13 7 8
样例输出
43
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=105;
int n;
int dp[N][N], L[N], s[N][N];
int main() {
scanf( "%d", &n );
for( int i=1; i<=n; i++ ) scanf( "%d", &L[i] );
for( int i=1; i<=n; i++ )
for( int j=i; j<=n; j++ )
s[i][j]=s[i][j-1]+L[j];
for( int len=2; len<=n; len++ )//石子堆长度
for( int i=1; i<=n; i++ ) {//石子堆起点
int j=i+len-1;//石子堆终点
dp[i][j]=INF;
for( int k=i; k<j; k++ )//分开算i->j
dp[i][j]=max( dp[i][j], dp[i][k]+dp[k+1][j]+s[i][j] );
}
printf( "%d\n", dp[1][n] );
return 0;
}