[经典dp]石子合并

设有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; 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值