题310.区间dp-acwing-Q1068--环形石子合并


题310.区间dp-acwing-Q1068–环形石子合并


一、题目

在这里插入图片描述

二、题解

用dp五步法分析该题(以求最大得分为例):
1.确定dp数组,并明确其含义。dp[l][r]表示[l,r]区间石子合并所能得到的最大得分
2.确定递推公式,对于链状的石子合并问题用y式dp分析法。
在这里插入图片描述
则递推公式如下:
dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]+(sum[r]-sum[l]))
3.初始化dp数组。当区间长度为1时,无需合并显然得分为0,即对于dp值初始化为0,由于求max,所以其余初始化为-Inf
4.确定遍历顺序。这是一个环形石子合并问题,为了处理这个环形,我们可以采用将环拉成链的形式,即把输入链延长两倍,变成 2n 个石堆,其中 i 和 i+n 是相同的两个堆,然后直接套之前确定的递推公式求解。而此时需用len从前向后遍历区间长度([1,n]),l从前向后遍历左端点,并确定r(<2n),k从前向后遍历分界点(分法,[1,r))
5.打印dp数组
代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=410;
const int Inf=0x3f3f3f3f;

int n;
int a[maxn],sum[maxn];
int dp_min[maxn][maxn],dp_max[maxn][maxn];//[l][r]区间,合并得分的最小值,最大值

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)//将环形拉成一条链,方法就是再补一条原链在原链的尾巴后面
    {
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++)//预处理得到前缀和,方便后序区间合并求对应区间的石子总数
    {
        sum[i]=sum[i-1]+a[i];
    }
    fill(dp_min[0],dp_min[0]+maxn*maxn,Inf);
    fill(dp_max[0],dp_max[0]+maxn*maxn,-Inf);
    for(int len=1;len<=n;len++)//枚举区间长度
    {
        for(int l=1;l+len-1<=2*n-1;l++)//枚举左端点,由于是原链+原链,所以l+len-1对应右端点的位置最大可达2*n-1(如果到2n,则会l=n+1,r=2n,此时和1~n石子取重了)
        {
            int r=l+len-1;//得到右端点
            if(len==1)//当区间长度为1时,不用合并,所以得分自然为0
            {
                dp_min[l][r]=dp_max[l][r]=0;
            }
            else//枚举区间分割点
            {
                for(int k=l;k<r;k++)
                {
                    //k位置分割对应的dp值为k之前的dp值(由于先求的小区间,已保证该值为对应最小/大,k之后同理)+k之后的dp值+整个lr区间的石子总数
                    dp_min[l][r]=min(dp_min[l][r],(dp_min[l][k]+dp_min[k+1][r]+sum[r]-sum[l-1]));
                    dp_max[l][r]=max(dp_max[l][r],(dp_max[l][k]+dp_max[k+1][r]+sum[r]-sum[l-1]));
                }
            }
        }
    }
    int res_min=Inf,res_max=-Inf;
    for(int i=1;i<=n;i++)//枚举原链+原链中选择不同的n长度区间,看哪个为结果值
    {
        res_min=min(res_min,dp_min[i][i+n-1]);
        res_max=max(res_max,dp_max[i][i+n-1]);
    }
    cout<<res_min<<endl;
    cout<<res_max<<endl;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值