Pangu and Stones 北京2017ICPC(三维区间DP)

题意:

合并石子的升级版。一堆石子,编号为1到n,每堆石子有其权值,一次只能合并连续的石子L到R堆,每次合并的代价为各堆石子的权值,求最后一堆的最小代价,不能完成输出0。

思路:

考虑区间dp做法,因为这个题与堆数有关,dp中加入一维堆数。

dp[i[[j][p]表示石子从i到j合并成p堆的最小花费,状态很重要。

状态转移:

当p>1&&i<=k<j(不表示合并,只表示合并的方案)

dp[i][j][p]=dp[i][k][1]+dp[k+1][j][p-1](表示区间i到j分成p堆的方案枚举,因为p堆总数1堆+p-1堆)

当p==1&&L<=p<=R(表示真正的合并)

dp[i][j][1]=dp[i][j][p]+pre[j]-pre[i-1]。

初始化:

扫描二维码关注公众号,回复: 7140241 查看本文章

求最小,首先f把需要用的的数组范围内的初始化INF

dp[i][i][1]=0,表示没有合并的自己不需要代价

也存在一些边界条件处理,自己注意一下即可。

代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int dp[N][N][N];//区间i到j分成k堆的最小代价
const int INF=0x3f3f3f3f;
int a[N];
int pre[N];
void init(int n){
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++){
        pre[i]=pre[i-1]+a[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                dp[i][j][k]=INF;
    for(int i=0;i<N;i++)
        dp[i][i][1]=0;
}
int main()
{
    int n,l,r;
    while(~scanf("%d%d%d",&n,&l,&r)){
        init(n);
    for(int len=1;len<=n;len++)
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            for(int p=2;p<=len;p++)
            {
                for(int k=i;k<j&&j-k>=p-1;k++)
                {
                    dp[i][j][p]=min(dp[i][j][p],dp[i][k][1]+dp[k+1][j][p-1]);
                    if(p>=l&&p<=r)dp[i][j][1]=min(dp[i][j][1],dp[i][j][p]+pre[j]-pre[i-1]);
                }
            }
    }
    if(dp[1][n][1]==INF){
        printf("0\n");
    }
    else{
        printf("%d\n",dp[1][n][1]);
    }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/gzr2018/p/11438390.html