4457: 【入门】石子合并(环形)(2058)
内存限制:128 MB
时间限制:1.000 S
评测方式:文本比较
命题人:
提交:3
解决:2
题目描述
在一个圆形操场的四周摆放 堆石子,现要将石子有次序地合并成一堆。规定每次只能选相邻的 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将 堆石子合并成 堆的最小得分和最大得分。
输入
数据的第 行是正整数 ,表示有 堆石子。
第 行有 个整数,第 个整数 表示第 堆石子的个数。
。
输出
输出共 行,第 行为最小得分,第 行为最大得分。
样例输入 复制
4
4 5 9 4
样例输出 复制
43
54
提示
#include<bits/stdc++.h>
using namespace std;
/*
将数据规模翻倍,将a数组完整接贝一遍求
区间最长长度为的情况下,合并得到的最优解
再从每个可能的起点出发,打播台求最小、最大值
*/
const int N= 410;
int a[N*2],s[N*2]; //s:前缀和
int mi[N*2][N*2],ma[N*2][N*2];
int n;
int main(){
cin>>n; //初始化
memset(mi,0x3f,sizeof(mi));
memset(ma,-0x3f,sizeof(ma));
for(int i= 1;i<= n;i++){
cin>>a[i];
a[i+n]= a[i]; //数组完整的赋值一遍
}
for(int i=1;i<= n*2;i++) {
s[i]=s[i-1]+a[i];
mi[i][i]= 0;
ma[i][i]= 0;
}
//初始化
//区间dp求解
//穷举所有可能的区间长度
for(int len=2;len<= n;len++){
//穷举区间的左端点
for(int i=1;i+len-1<= n* 2;i++){
//右端点
int j=i+len-1;
//穷举分割点
for(int k= i;k< j;k++){
mi[i][j]=min(mi[i][j],mi[i][k]+mi[k+1][j]+s[j]-s[i-1]);
ma[i][j]=max(ma[i][j],ma[i][k]+ma[k+1][j]+s[j]-s[i-1]);
}
}
}
//穷举所有可能的出发点,打擂台求最小、最大
int minn = INT_MAX,maxn = INT_MIN;
for(int i= 1;i<= n;i++){
minn = min(minn,mi[i][i+n-1]);
maxn = max(maxn,ma[i][i+n-1]);
}
cout<<minn<<endl<<maxn;
return 0;
}