hihocoder1636 ACM-ICPC北京赛区2017网络同步赛 J题 (区间DP)

7 篇文章 0 订阅

题目链接:https://hihocoder.com/problemset/problem/1636

题意:给定n,l,r三个参数和一个长度为n的数组p,每次可以将长度为x(l<=x<=r)的连续区间合并为一个点,代价为该区间和值,该点的权值也为该区间和值,问将p数组合为一个点所需的最小代价和,若不能合并为一个点,则输出0

思路:区间dp,先遍历所有可能区间的长度,按照区间长度遍历所有区间,dp[i][j][k]表示从i到j区间合成k个堆的最小代价和,给其付初值均为inf,将dp[i][j][j-i+1]均赋为0,状态转移方程如下: 

                                                  dp[i][i+d][1] = min(dp[i][i+d][1],dp[i][u][a]+dp[u+1][i+d][1]+sum[j] - sum[i-1]), l<=a+1<=r, i<=u<i+d

                                                  dp[i][i+d][k] = min(dp[i][i+d][k],dp[i][u][k-1]+dp[u+1][i+d][1]),1<k<=d+1

代码:

/*#include <bits/stdc++.h>*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long ll;
const ll mod = 2147493647;
const int maxn = 105;
const double eps = 1e-8;
const ll inf = 10000000000000;

ll dp[maxn][maxn][maxn];
int n, l, r;
ll p[maxn];
ll sum[maxn];

int main()
{
    while(~scanf("%d%d%d",&n,&l,&r))
    {
        for(int i=0;i<105;i++)
        {
            for(int j=i;j<105;j++)
            {
                for(int k=0;k<105;k++)
                    dp[i][j][k] = inf;
                dp[i][j][j-i+1] = 0;
            }
        }
        sum[0] = 0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&p[i]);
            sum[i] = sum[i-1]+p[i];
        }
        for(int d = 1;d<n;d++)
        {
            for(int i=1;i+d<=n;i++)
            {
                int j = i+d;
                for(int u = i;u<j;u++)
                {
                    for(int a = l-1;a<r;a++)
                    {
                        if(a>u-i+1)break;
                        if(dp[i][u][a]>=inf || dp[u+1][j][1]>=inf)continue;
                        dp[i][j][1] = min(dp[i][j][1],dp[i][u][a]+dp[u+1][j][1]+sum[j] - sum[i-1]);
                    }
                    for(int a = 1;a<=u-i+1;a++)
                    {
                        if(dp[i][u][a]>=inf || dp[u+1][j][1]>=inf)continue;
                        dp[i][j][a+1] = min(dp[i][j][a+1],dp[i][u][a]+dp[u+1][j][1]);
                    }
                }
            }
        }
        if(dp[1][n][1]>=inf)
            printf("0\n");
        else
            printf("%lld\n",dp[1][n][1]);
    }

}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值