题目描述
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.(N≤100)
输入
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出
输出共2行,第1行为最小得分,第2行为最大得分.
样例输入
4 4 5 9 4
样例输出
43 54
练练区间dp,把环扩展成2n长度的链就行了,记f[i][j]为i~j的最优解
f[i][j]=min/max(f[i][j],f[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define ll long long using namespace std; const int maxn=1005; const int inf=0x7f7f7f7f; inline int read(){ int x=0,k=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return k*x; } int f1[maxn][maxn],f2[maxn][maxn],g[maxn],sum[maxn]; int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); int n,maxx=0,minn=inf; n=read(); for(int i=1;i<=n;i++){ g[i]=read(); g[i+n]=g[i]; } for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+g[i]; for(int i=2*n-1;i;i--) for(int j=i+1;j<=i+n;j++){ f1[i][j]=inf; for(int k=i;k<j;k++){ f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]); f2[i][j]=max(f2[i][j],f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1]); } } for(int i=1;i<=n;i++){ minn=min(minn,f1[i][i+n-1]); maxx=max(maxx,f2[i][i+n-1]); } cout<<minn<<endl<<maxx; return 0; }