码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-08-31 13:13:05      阅读:84      评论:0      收藏:0      [点我收藏+]

标签:北京   size   lse   nes   nbsp   icp   数组   else   style   

题意:

合并石子的升级版。一堆石子,编号为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]。

初始化:

求最小,首先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;
}

 

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

标签:北京   size   lse   nes   nbsp   icp   数组   else   style   

原文地址:https://www.cnblogs.com/gzr2018/p/11438390.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!