【题解】合并石子

题面

【题目描述】
有一排石子,共n 堆。现要将石子有次序地合并成一堆。
规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将n堆石子合并成一堆的最小得分。
【输入】
第一行为一个正整数N(2<=N<=100);
以下N行,每行一个正整数,小于10000,分别表示第I堆石子的个数(1<=I<=N)。
【输出】
一个正整数,即最小得分。
【样例输入】

7
13
7
8
16
21
4
18

【样例输出】

239

算法分析

区间型DP
状态:
d p [ i ] [ j ] dp[i][j] dp[i][j]——合并第 i i i堆石子~第 j j j堆石子的最小得分。
当第 i i i堆石子~ 第 j j j堆石子合并成一堆之前,肯定是由某两堆合并而来的,这里进行枚举,假设是由一堆(第 i i i堆石子 ~ 第 k k k堆石子合并后的一堆),另一堆(第 k + 1 k+1 k+1堆石子 ~ 第 j j j堆石子合并后的一堆),这两堆合并。合并的得分为第 i i i堆石子~ 第 j j j堆石子的石子总数,这里可以使用前缀和。
状态转移方程
d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] , d p [ k + 1 ] [ j ] ) + s u m [ i ] − s u m [ j − 1 ] dp[i][j]=min( dp[i][k] , dp[k+1][j] ) + sum[i]-sum[j-1] dp[i][j]=min(dp[i][k],dp[k+1][j])+sum[i]sum[j1],( i < = k < = j i<=k<=j i<=k<=j s u m [ i ] sum[i] sum[i]为前缀和)
边界
f [ i ] [ i ] = 0 f[i][i]=0 f[i][i]=0,只有一堆时,得分为 0 0 0.
合并第 1 1 1堆~第 n n n堆的最小值就是 f [ 1 ] [ n ] f[1][n] f[1][n]

参考程序

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int s[110],dp[110][110];
int main()
{
    int n,a;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a;
        s[i]=s[i-1]+a;		//前缀和
    }
    memset(dp,127/3,sizeof(dp));	//初始化为较大值
    for(int i=1;i<=n;i++)    dp[i][i]=0;	//边界条件
    for(int i=n-1;i>=1;i--)
        for(int j=i+1;j<=n;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]);
    cout<<dp[1][n]<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值