其他分享
首页 > 其他分享> > 1030 石子合并 区间DP

1030 石子合并 区间DP

作者:互联网

链接:https://ac.nowcoder.com/acm/contest/24213/1030
来源:牛客网

题目描述

将n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数n及每堆的石子数,并进行如下计算:
  1. 选择一种合并石子的方案,使得做n-1次合并得分总和最大。
  2. 选择一种合并石子的方案,使得做n-1次合并得分总和最小。

输入描述:

输入第一行一个整数n,表示有n堆石子。
第二行n个整数,表示每堆石子的数量。

输出描述:

第一行为合并得分总和最小值,
第二行为合并得分总和最大值。
示例1

输入

复制
4
4 5 9 4

输出

复制
43
54

备注:

对于100%100 \%100%的数据,有1≤n≤2001 \leq n \leq 2001≤n≤200。

分析

石子合并,经典的小区间到大区间问题,且时间复杂度是n^2 ,所以区间DP

用前缀和维护,可以算出合并一段区间所需要的能量

 

易错点

1.石子数量从2开始取

2.算最小值的时候,要把当前要算的区间的DP值置无穷

//-------------------------代码----------------------------

//#define int LL
const int N = 500;
int n,m;
int a[N],f[N][N],dp[N][N];

 

void solve()
{
// ms(f,inf);
cin>>n;
for(int i = 1;i <= n;i ++){
cin>>a[i];
a[i + n] = a[i];
}
for(int i = 1;i <= 2 * n;i ++){
a[i] += a[i - 1];
}
int mx = -inf,mn = inf;
for(int k = 2;k<=n;k++) {
for(int i = 1,j = k;j<=2*n;j++,i++) {
f[i][j] = inf;//要注意当前值一定要无穷大,其它值一定要0,才能转化。。
for(int k = i;k<j;k++) {
f[i][j] = min(f[i][j],f[i][k] + f[k+1][j] + a[j] - a[i-1]);
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[j]-a[i-1]);
}
}
}
fo(i,1,n) {
mx = max(mx,dp[i][i + n - 1]);
mn = min(mn,f[i][i + n - 1]);
}
cout<<mn<<endl<<mx<<endl;
}

signed main(){
clapping();TLE;

// int t;cin>>t;while(t -- )
solve();
// {solve(); }
return 0;
}

/*样例区


*/

//------------------------------------------------------------

标签:得分,int,石子,合并,DP,1030,inf,dp
来源: https://www.cnblogs.com/er007/p/16468593.html