【补】石子合并

题目描述

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

输入输出格式

输入格式:

 

数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

 

输出格式:

 

输出共2行,第1行为最小得分,第2行为最大得分.

 

输入输出样例

输入样例#1: 复制
4
4 5 9 4
输出样例#1: 复制
43
54


有切环的操作

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define mst(a,b) memset((a),(b),sizeof(a))  
#define rush() int T;scanf("%d",&T);while(T--) 
using namespace std;

typedef long long ll;  
const int maxn = 2050;  
const ll mod = 1e9+7;  
const ll INF = 1e18; 
const ll in=0x3f3f3f3f; 
const double eps = 1e-9;  
  
ll n,x[maxn<<1],mmin=INF,mmax;  
ll sum[maxn<<1];  
ll dp1[maxn][maxn<<1];  
ll dp2[maxn][maxn<<1];
int main(){
    cin>>n;
    sum[0]=0;
    for(int i=1;i<=n;i++){
        cin>>x[i];
        x[i+n]=x[i];
    }
    for(int i=1;i<=n<<1;i++){
        sum[i]=sum[i-1]+x[i];
    }//切割圆
    for(int i=(n<<1)-1;i>0;i--){
    for(int j=i+1;j<i+n;j++){
    //mst(dp1,maxn);
//    mst(dp2,maxn);
    dp1[i][j]=in;
        for(int k=i;k<j;k++){
            dp1[i][j]=dp1[i][j]>dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]?
            dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]:dp1[i][j];
            dp2[i][j]=dp2[i][j]>dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]?
            dp2[i][j]:dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1];
        }
    }
}
    for(int i=1;i<=n;i++){
        mmin=mmin>dp1[i][i+n-1]?dp1[i][i+n-1]:mmin;
        mmax=mmax>dp2[i][i+n-1]?mmax:dp2[i][i+n-1];
    }
    cout<<mmin<<endl;
    cout<<mmax;
}

 

posted @ 2018-08-24 17:06  东方的古文明  阅读(111)  评论(0编辑  收藏  举报