P1880 [NOI1995]石子合并
题目描述
在一个圆形操场的四周摆放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
区间dp :
#include<bits/stdc++.h>
using namespace std;
int n,a[305],sum[305],dp[305][305],dd[305][305],minn,maxn;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[n+i]=a[i];//断环为链
}
for(int i=1;i<=n*2;i++)
sum[i]=sum[i-1]+a[i];//前缀和
for(int l=2;l<=n;l++)//区间长度
{
for(int i=1;i<=n*2-l+1;i++)//左端点
{
int j=i+l-1;//右端点
dp[i][j]=0x3f3f3f3f;
dd[i][j]=0;
for(int k=i;k<j;k++) //以k为中间值 合并
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
dd[i][j]=max(dd[i][j],dd[i][k]+dd[k+1][j]+sum[j]-sum[i-1]);
}
}
}
minn=0x3f3f3f3f;
for(int i=1;i<=n;i++)//求出最大 最小值 区间长度都为 n
{
minn=min(minn,dp[i][i+n-1]);
maxn=max(maxn,dd[i][i+n-1]);
}
cout<<minn<<endl;
cout<<maxn<<endl;
return 0;
}