题意:
有n堆石子,第i堆的数量为a(i),
每次只能将连续的石子合并为一堆,代价为这些石子总数量,要求合并的堆数在[L,R]之间。
求将所有石子合并为一堆的最小代价。
如果无解输出0.
数据范围:n<=100
解法:
比普通的石子合并多了一个堆数的限制
-----分割线-----
claris的题解:
普通的石子合并,f[l][r]表示将[l,r]合并为一堆的最小代价,
通过枚举分割点进行转移:
f[l][r]=min{f[l][k]+f[k+1][r]}
这题f[l][r][k]表示[l,r]合并成k堆的最小代价
g[l][r]表示[l,r]合并为一堆的最小代价
f[l][r][k]=min{f[l][x][k-1]+g[x+1][r]},
g[l][r]=min{f[l][r][x]}+sum(l,r),其中L<=x<=R
-----分割线-----
g[l][r]可以用f[l][r][1]代替
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=105;
int d[maxm][maxm][maxm];
int sum[maxm];
int a[maxm];
int n,L,R;
signed main(){
while(scanf("%d%d%d",&n,&L,&R)!=EOF){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
//init
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
d[i][j][k]=1e9;
}
}
}
for(int i=1;i<=n;i++)d[i][i][1]=0;
//
for(int len=1;len<=n;len++){//区间长度
for(int i=1;i<=n;i++){//区间左端点
int j=i+len-1;
if(j>n)break;//区间右端点
for(int k=2;k<=min(R,len);k++){//堆数
for(int x=i;x<j;x++){//切点
d[i][j][k]=min(d[i][j][k],d[i][x][k-1]+d[x+1][j][1]);
}
if(k>=L)d[i][j][1]=min(d[i][j][1],d[i][j][k]+sum[j]-sum[i-1]);//g[i][j]
}
}
}
if(d[1][n][1]==1e9)d[1][n][1]=0;
printf("%d\n",d[1][n][1]);
}
return 0;
}