题目链接
题目大意
有n个石子,每次选择连续的大于等于L个且小于等于R个的石子合并,问最后合并成一堆石子的最小花费
解题思路
区间dp还是很明显的,不过要加一维,是dp[i][j][k]的意思是i到j这个区间分成k堆的最小花费
感觉自己的dp学的还是不行,就多了一维差点给我搞去世
当k==1的时候:
dp[i][j][1] = min ( dp[i][j][1] , dp[i][p][x] + dp[p+1][j][1] + sum[j] - sum[i-1]);
其中p是i到j之间的断点,x是断点前有多少堆所以根据题意x<R&&x>L
当k>1的时候
dp[i][j][p] = min ( dp[i][j][p] , dp[i][k][p-1] + dp[k+1][j][1]);
其中k是断点
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=105;
const long long inf=0x3f3f3f3f3f3f3f3f;
long long dp[N][N][N],a[N],sum[N];
int main()
{
int n,L,R;
while(~scanf("%d %d %d",&n,&L,&R))
{
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
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++)
for(int j=i; j<=n; j++)
dp[i][j][j-i+1]=0;
for(int len=1; len<=n; len++)
{
for(int i=1; i+len<=n; i++)
{
int j=i+len;
//dp[i][j][1]=inf;
for(int p=i; p<j; p++)
{
for(int x=L-1; x<R; x++)
dp[i][j][1]=min(dp[i][j][1],dp[i][p][x]+dp[p+1][j][1]+sum[j]-sum[i-1]);
}
for(int p=2; p<=len; p++)
{
//dp[i][j][p]=inf;
for(int k=i; k<j; k++)
{
dp[i][j][p]=min(dp[i][j][p],dp[i][k][p-1]+dp[k+1][j][1]);
}
}
}
}
if(dp[1][n][1]<inf)
printf("%lld\n",dp[1][n][1]);
else
printf("0\n");
}
return 0;
}