石子合并2——区间DP【洛谷P1880题解】

【区间dp让人头痛……还是要多写些题目练手,抽空写篇博客总结一下】


 

这题区间dp入门题,理解区间dp或者练手都很妙

——题目链接——

(或者直接看下面)

题面

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

范围:1≤N≤100

分析

这个范围……感受到快乐了吗?

一般这种范围复杂度都超高哦~

 这题是区间DP,我想看标题就知道了,如果没有学过区间DP的话……就先学吧(这个坑可能我得好久好久好久以后填)

 这题四舍五入就是个模板(?)了

难点在于它是个环,不过处理起来难度也不大

 我们把这个环破开复制一遍,那么它会成为一条链,就会便于 处理啦

在这个 2*n (复制过一遍)的数组上枚举 1~n 的区间就能得到这个环能组成的所有区间

然后就是区间DP的实现过程!(不懂试着看看代码,再不懂就找找博客 / 老师学一学)

转移方程式:

dpmax[j][ends]=max(dpmax[j][ends],dpmax[j][i]+dpmax[i+1][ends]+stone[ends]-stone[j-1]);
dpmin[j][ends]=min(dpmin[j][ends],dpmin[j][i]+dpmin[i+1][ends]+stone[ends]-stone[j-1]);

【 j 和 ends 是目前区间左右端点, i 是枚举的 j~ends 里的一点,用于断开区间更新dp数组】

【 stone 数组记录整段区间前缀和,便于统计数据; dpmax 和 dpmin 看名字估计也知道是干什么了吧】

放一张AC图(悄咪咪地)我知道我很菜鸡你们自己考虑看不看下面参考

代码参考

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,a[101],stone[401];
int dpmax[205][205];
int dpmin[205][205];
int main()
{
    cin>>n;
    for (int i=1; i<=n; i++)
    {
        cin>>a[i];
    }
    memset(dpmax,-1,sizeof(dpmax));
    memset(dpmin,0x3f3f3f,sizeof(dpmin));
    memset(stone,0,sizeof(stone));
    for (int i=1; i<=n; i++)
    {
        stone[i]=stone[i-1]+a[i];
        dpmax[i][i]=0;
        dpmin[i][i]=0;
    }
    for (int i=1; i<=n; i++)
    {
        stone[i+n]=stone[i+n-1]+a[i];
        //stone记录前缀和,用前缀和处理比较轻松 
        dpmax[i+n][i+n]=0;
        dpmin[i+n][i+n]=0;
    }
    //读入与初始化 
    for (int len=1; len<=n; len++)
    //len枚举区间长度 
    for (int j=1; j+len<=2*n; j++)
    //j枚举区间左端点 
    {
        int ends=j+len-1;
        //区间右端点 
        for (int i=j; i<ends; i++)
        //枚举分割点 
        {
            dpmax[j][ends]=max(dpmax[j][ends],dpmax[j][i]+dpmax[i+1][ends]+stone[ends]-stone[j-1]);
            dpmin[j][ends]=min(dpmin[j][ends],dpmin[j][i]+dpmin[i+1][ends]+stone[ends]-stone[j-1]);
        }
    }//核心代码!!!状态转移 
    int ansmin=0x3f3f3f;
    int ansmax=-1;
    for (int i=1; i<=2*n; i++)
    {
        ansmin=min(ansmin,dpmin[i][i+n-1]);
        //i+n-1刚好是每种区间,超级妙的思路 
        ansmax=max(ansmax,dpmax[i][i+n-1]);
    }
    cout<<ansmin<<endl<<ansmax;
    return 0;
}
——撒花!!!!—— 

 

我是在网上找博客学的区间DP,大概是有部分参考

—>https://blog.csdn.net/qq_40772692/article/details/80183248

有问题欢迎大佬指正

到这里就结束了,感谢看完

ありがとうございます

posted @ 2019-10-06 08:56  莳萝萝  阅读(228)  评论(0编辑  收藏  举报