描述
将 n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
选择一种合并石子的方案,使得做 n−1次合并得分总和最小。
输入
输入第一行一个整数 n,表示有 n 堆石子。
第二行 n 个整数,表示每堆石子的数量。
输出
输出共两行:
第一行为合并得分总和最小值,
第二行为合并得分总和最大值。
样例输入
4
4 5 9 4
样例输出
43
54
提示
对于 100% 的数据,有1≤n≤200
区间dp基础题啊
从长度从小往大枚举
然后枚举左端点
枚举中间点
取max就可以了
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
int n,f[405][405],g[405][405],a[405],sum[405];
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=a[i+n]=read();
}
memset(f,127/3,sizeof(f));
for(int i=1;i<=2*n;i++){
sum[i]=sum[i-1]+a[i];
f[i][i]=g[i][i]=0;
}
for(int len=2;len<=2*n;len++){
for(int l=1;l<=2*n-len+1;l++){
if(l+len>2*n)break;
int r=l+len-1;
for(int k=l;k<=r;k++){
f[l][r]=min(f[l][k]+f[k+1][r],f[l][r]);
g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]);
}
f[l][r]+=(sum[r]-sum[l-1]);
g[l][r]+=(sum[r]-sum[l-1]);
}
}
int maxn=0,minn=1e9;
for(int i=1;i<=n;i++){
maxn=max(maxn,g[i][i+n-1]);
minn=min(minn,f[i][i+n-1]);
}
cout<<minn<<'
'<<maxn;
}