题目链接
题意:
将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
选择一种合并石子的方案,使得做 n−1 次合并得分总和最小
分析:
这个题是石子合并的升级版,那么现在问题就落到了怎么将这个题转化到石子合并的问题上,那么就会想到将这n个序列复制一遍放在这个序列的后面,然后再进行一次石子合并,从长度为n的序列中找出答案即可,现在请看代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 410;
int a[N],s[N],f1[N][N],f2[N][N];
int main(){
int n;
cin>>n;
memset(f1,0x3f,sizeof f1);
for(int i=1;i<=2*n;i++) f1[i][i] = 0;
for(int i=1;i<=n;i++) cin>>a[i],s[i] = s[i-1] + a[i];
for(int i=n+1;i<=2*n;i++) a[i] = a[i-n],s[i] = s[i-1] + a[i];
for(int len=2;len<=n;len++){
for(int i=1;i<=2*n-len+1;i++){
int j = i + len - 1;
for(int k=i;k<j;k++){
f1[i][j] = min(f1[i][j],f1[i][k]+f1[k+1][j]+s[j]-s[i-1]);
f2[i][j] = max(f2[i][j],f2[i][k]+f2[k+1][j]+s[j]-s[i-1]);
}
}
}
int ans2 = 0,ans1 = 0x3f3f3f3f;
for(int i=1;i<=n+1;i++){
ans1 = min(ans1,f1[i][i+n-1]);
ans2 = max(ans2,f2[i][i+n-1]);
}
cout<<ans1<<endl<<ans2<<endl;
return 0;
}