nyoj 737 石子合并(区间DP)

737-石子合并(一)

内存限制:64MB

       

时间限制:1000ms

       

特判: No
通过数:28

       

提交数:35

       

难度:3



题目描述:

    有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。

输入描述:

有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开

输出描述:

输出总代价的最小值,占单独的一行

样例输入:

3
1 2 3
7
13 7 8 16 21 4 18

样例输出:

9
239

题目大意:

给你n堆石子,每堆石子有ai个。你每次可以把两堆石子合并到一块,代价为总的石子数。问最少需要多少代价将n堆石子合为一堆。

最基本的区间dp问题。枚举区间长度,区间,和划分。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200;
const int inf=1000000000;
int a[maxn+10];
int sum[maxn+10][maxn+10];
int dp[maxn+10][maxn+10];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=2;i<=n;i++)
            a[i]+=a[i-1];
        a[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
                sum[i][j]=a[j]-a[i-1];
        memset(dp,0,sizeof(dp));
        for(int len=2;len<=n;len++)//直接跳过长度为1的区间,默认为0
        {
            for(int left=1;left<=n;left++)
            {
                int right=left+len-1;
                if(right>n)
                    break;
                int val=inf;
                for(int mid=left;mid<right;mid++)
                    val=min(val,dp[left][mid]+dp[mid+1][right]);
                dp[left][right]=val+sum[left][right];
                //printf("%d %d %d
",left,right,dp[left][right]);
            }
        }
        printf("%d
",dp[1][n]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/acboyty/p/9745893.html