【补】石子合并
题目描述
在一个圆形操场的四周摆放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; }