HihoCoder - 1636 Pangu and Stones (区间DP)

题目链接

题意:给你n堆石头a[n]--每堆石头的数目,每次只能合并L~R堆石头,且每次合并需要消耗sum[i,j]的时间,求合并成一堆的最小时间。

题解:很明显使用区间dp做,状态转移方程如下:
      dp[i][j][k]表示从i到j有k堆的最小时间
      k==1,dp[i][j][1]=min(...,dp[i][p][k-1]+dp[p+1][j][1]+sum[i][j]);
                                                    i<p<j         L<=k<=R
      k>=2, dp[i][j][k]=min(...,dp[i][p][k-1]+dp[p+1][j][1]);

代码如下:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
LL sum[105][105];
LL dp[105][105][105];
int a[105];
int main()
{
    int n,l,r;
    while(~scanf("%d%d%d",&n,&l,&r))
    {
	for(int i=1;i<=n;i++)
	    scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	    for(int j=i;j<=n;j++)
		sum[i][j]=sum[i][j-1]+a[j];
	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 d=1;d<n;d++)
	    for(int i=1;i+d<=n;i++)
	    {
		int j=i+d;
		for(int p=i;p<j;p++)
		    for(int k=l;k<=r;k++)
			dp[i][j][1]=min(dp[i][j][1],dp[i][p][k-1]+dp[p+1][j][1]+sum[i][j]);
		for(int k=2;k<=d;k++)
		    for(int p=i;p<j;p++)
			dp[i][j][k]=min(dp[i][j][k],dp[i][p][k-1]+dp[p+1][j][1]);
	    }
	if(dp[1][n][1]>=inf)
	    cout<<0<<endl;
	else
	    cout<<dp[1][n][1]<<endl;
    }     
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81810329