链接:https://hihocoder.com/problemset/problem/1636
石子归并变形版本。
在原有石子归并问题上。增加合并堆数的限制。
原有石子归并一次必须合并
2
堆
现在一次必须合并 k 堆
k∈[L,R]
,也就是说合并的堆数不小于
L
,不大于R 。
每次合并的耗费。依然是石子总重。
那么显然合并前。我们需要知道。有多少堆合并了。
对于堆数不在 [L,R] 的,不能合并。
令: dp[k][l][r]
区间
[l,r]
合并成
k
段的耗费。
w[l,r] 表示,区间
[l,r]
石子总重。
所以:
dp[k][l][r]=mint=l+k−2r−1(dp[k−1][l][t]+dp[1][t+1][r])
特别的当:
dp[1][l][r]=mink=LR(dp[k][l][r]+w[l,r])
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define MAXN 110
using namespace std;
const int INF=1e9;
int dp[MAXN][MAXN][MAXN];
int W[MAXN];
int D[MAXN];
int main ()
{
int n,L,R;
while(scanf("%d %d %d",&n,&L,&R)==3)
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
dp[i][j][k]=INF;
for(int i=1;i<=n;i++) scanf("%d",D+i);
for(int i=1;i<=n;i++) W[i]=W[i-1]+D[i];
for(int k=1;k<=R;k++)
for(int i=1,j=k;j<=n;i++,j++) dp[k][i][j]=0;
for(int len=L;len<=n;len++)
for(int l=1,r=len;r<=n;r++,l++)
for(int k=1;k<=R&&k<=len;k++)
{
for(int t=l+k-2;t<r;t++)
if(dp[k][l][r]>(dp[k-1][l][t]+dp[1][t+1][r]))
dp[k][l][r]=dp[k-1][l][t]+dp[1][t+1][r];
if(k>=L&&dp[1][l][r]>dp[k][l][r]+W[r]-W[l-1])
dp[1][l][r]=dp[k][l][r]+W[r]-W[l-1];
}
int ans=INF;
for(int i=L;i<=R;i++)ans=min(ans,dp[i][1][n]);
if(ans>=INF)
printf("0\n");
else
printf("%d\n",ans+W[n]-W[0]);
}
return 0;
}