• 石子合并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

    有问题欢迎大佬指正

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

    ありがとうございます

  • 相关阅读:
    【JAVA基础】正则表达式
    【JAVA基础】常用类的概述和使用
    【JAVA基础】反射机制
    献芹奏曝-Python面试题
    饮冰三年-人工智能-Python-65-Apollo之07 Docker环境部署
    饮冰三年-人工智能-Python-64-Apollo之06测试环境部署
    饮冰三年-人工智能-Docker-63-Docker部署文件帮助系统Mezzanine
    饮冰三年-人工智能-Python-62-ZooKeeper之04实战
    饮冰三年-人工智能-Python-61-ZooKeeper之03原理
    饮冰三年-人工智能-Python-60-ZooKeeper之02安装
  • 原文地址:https://www.cnblogs.com/Phantomhive/p/11625805.html
Copyright © 2020-2023  润新知