原题目如下:

看起来,这不过是我们在《程序设计基础》里面接触过的简单动态规划问题(
什么,你不知道什么叫动态规划?

什么是动态规划?

百度百科对“动态规划”一词定义如下:在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线.这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策问题。在多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,称这种解决多阶段决策最优化的过程为动态规划方法 。
但这样的定义谁也读不下去不是吗,因此,思考这样一个问题:
《程序设计基础》中,老师曾经讲过,对于“求斐波那契数列”这道题,用递推的办法比递归的办法更快。我们分别分析一下这两种办法。
假设我们需要求解f(6),对于递推法,我们只需要求解f5+f4,且这两者已经被我们求出来了。而对于递归法,f5和f4需要我们再调用函数求解,他们分别的求解过程中还需要继续套娃。。。
比较两种方法,我们不难发现,递推法把问题分成了若干小问题,而对于部分问题的解进行了存储,这样就使得如果我们希望多次调用一个中间值,无需反复递归求解。这就是一种dp(动态规划)的思想。
以这道题为例,我们就可以存储下每次取完石头后,对于不同位置的重量最大值,这样在进行下一步时,无需进行反复的递归。

用朴素的dp思想试做这道题

原题中对dp思想给予的温馨提示:

(其实这个提示已经将dp的具体实现告诉大家了)
读者可以自己尝试根据上述提示写出一个dp程序。
之所以这样dp,是因为如果确定了i轮选择和左边取出j个石头,无论前i-1的选择情况是怎样的,都不会对后续选择造成任何影响。

如果自己不能写出这个dp程序,下面是几点提示:
1.找到动态规划状态转移方程。dp就是由初始状态,边界条件,停止条件和状态转移方程组成的。对于这道题来说,在每个地方的状态转移方程都是等价的,没有什么特殊的干扰条件。
2.上述的i,j其实提示了实现循环的方法,可以发现按照这两个循环变量进行循环,恰好没有丢失或多步骤,而且步骤的顺序是满足本身的因果关系的。
3.最终得到的是一个一维数组,存储了左指针(j)在各个位置的选取最优解。只需在这些最优解中再取最优解即可。
如果你写出了这个dp程序,你会发现并不能够ac此题,而且,出现了一种罕见的错误类型,叫做:

如何降低空间复杂度?

本题的内存限制为20000kb,显然,并不能支撑我们开启1000*1000的二维数组。这就考验我们能否将空间复杂度进一步降低呢?
其实本题用到的优化也是在dp中非常常见的:我们发现,在状态转移方程中,第i轮的数值永远只和第i-1轮相关,而且我们在更新的时候,也是按照i的增加顺序更新的,也就是说,在更新第i次选取时,第i-2及以前的数据,我们是已经用不到的。这也就是说,我们可以用两个一维数组循环求解来代替原来的二维数组。
为了书写方便,我采用了一个第二维大小为2的二维数组。代码如下

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<string>
using namespace std;
int d[2][30005],g[30005];
inline void read(int&x){
char c,f=x=0;
while(!isdigit(c=getchar()))f=c=='-';
while(isdigit(c))x=x*10-48+c,c=getchar();
if(f)x=-x;
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)read(g[i]);
int p=0;
for(int k=1;k<=n/2;k++){
int q=p^1;
for(int r=0;r<=2*k;r++){ //左指针为r,即第r个石头在第k次后被取走了
if(!r)d[q][r]=d[p][r]+g[r+n+2-2*k];
else if(r==1)d[q][r]=max(d[p][r]+g[r+n+2-2*k],d[p][r-1]+max(g[r],g[r+n-2*k+1]));
else if(r==2*k-1)d[q][r]=max(d[p][r-1]+max(g[r],g[r+n-2*k+1]),d[p][r-2]+g[r-1]);
else if(r==2*k)d[q][r]=d[p][r-2]+g[r-1];
else d[q][r]=max(d[p][r-1]+max(g[r],g[r+n-2*k+1]),max(d[p][r-2]+g[r-1],d[p][r]+g[r+n+2-2*k]));
}
p=p^1;
}
int ma=0,k=n/2;
for(int i=2;i<=n+1;i++){ma=ma>d[k&1][i]?ma:d[k&1][i];}
printf("%d",ma);
}

(依然采用了快读,喜提472ms)
(求广大dalao教教如何进一步优化)

2021春季学期华清大学EE数算OJ3:岩石的重量的更多相关文章

  1. 2021夏季学期华清大学EE数算OJ2:难缠的店长

    2021年夏季学期华清大学电子系数算oj2题解 某知名oier锐评蒟蒻的oj1题解: 话不多说,进入oj2题解: 难缠的oj 之 难缠的店长 当时读完我已经因为无良甲方的行为出离愤怒了!但是做题还是要 ...

  2. 2021夏季学期华清大学EE数算OJ1:算数问题

    第一次写博客,有点紧张... 也许格式也没有特别丑吧 先看原题( 此题做法众多,这里仅仅介绍蒟蒻的一种很复杂的思路(但最后还是喜提0ms的好成绩) 读完这道题,不难发现,此题不过是一个质因数分解+一堆 ...

  3. 2019年春季学期第四周作业Compile Summarize

    这个作业属于哪个课程 C语言程序设计一 这个作业要求在哪里 2019春季学期第四周作业 我的课程目标 重新学习有关数组的问题 这个作业在哪个具体方面帮助我实现目标 对于置换有了新的见解 参考文献 中国 ...

  4. 毕业样本=[华威大学毕业证书]Warwick原件一模一样证书

    华威大学毕业证[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归& ...

  5. 热烈庆祝华清远见2014嵌入式系统(Linux&Android)开发就业培训课程全面升级

    近日,华清远见公开宣布:2014嵌入式系统 (Linux&Android)开发就业培训课程再次升级!据悉,华清远见如今已经持续10年,一直保持课程每年2次的更新的频率.华清远见的每 次课程更新 ...

  6. 百度前端技术学院(IFE)2016春季学期总结

    今天(5月16日)作为第八个提交者提交了任务五十:RIA微型问卷管理平台 这样一个综合性的大任务,宣告我的IFE春季学期课程学习顺利完成.其实任务五十并不复杂,现在再让我来做,可能一周不到就写出来了, ...

  7. 2019年春季学期《C语言程序设计II》助教注意事项

    本学期<C语言程序设计II>课程安排 理论课时24(1-12周),实验课时8(13周),课程设计课时16(14-15周) 理论课教学内容 附:教学进度表 本学期实验课和课程设计参考教材 & ...

  8. 2019年春季学期《C语言程序设计II》课程总结

    2019年春季学期<C语言程序设计II>课程总结 1.课程情况 教学内容 课堂小结 作业安排 优秀作业 备注 1.开学谈心 2.测验数据类型.运算符与表达式的自学情况,并讲解测验题目3.第 ...

  9. 基于华清远见STM32f051的 IIC从模式实现方法

    作者:卢老师,华清远见嵌入式学院讲师. 在大多情况下,我们使用MCU控制传感器,节点以及相关从设备,但在较为复杂的系统中,有时候也会使用MCU做为从设备. 下面是关于stm32f051的从模式实现方法 ...

随机推荐

  1. About HTML

    HTML 简介 HTML 历史 最初的 HTMl 是由 CERN负责制定的,后来转交给 IETF. 在 1990-1995 年期间, HTML 经历了许多次的版本修改与扩充: 1995 年的时候 HT ...

  2. ionic的checkbox分析

    之前分析了一个原生的checkbox,趁热打铁分析ionic的自带checkbox. html <label class="checkbox"> <input t ...

  3. 现在做 Web 全景合适吗?

    Web 全景在以前带宽有限的条件下常常用来作为街景和 360° 全景图片的查看.它可以给用户一种 self-immersive 的体验,通过简单的操作,自由的查看周围的物体.随着一些运营商推出大王卡等 ...

  4. Ubuntu之安装Gradle

    简介 Gradle 是以 Groovy 语言为基础,面向Java应用为主,基于DSL(领域特定语言)语法的自动化构建工具. 现在Android Studio用它来编译APK程序. 前提 Ubuntu官 ...

  5. Android优化应用启动速度

    一.应用的启动 启动方式 通常来说,在安卓中应用的启动方式分为两种:冷启动和热启动. 1.冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动 ...

  6. java对象有什么重要的?

    3.历史上讲,对象有什么重要的?  [新手可忽略不影响继续学习]早期的编程主要是面向过程的编程,处理的问题都相对的简单,比较过程化,换句话说,就是一步一步从开始到结束,比如第一步进入电梯,第二步关门, ...

  7. Android Studio项目导入方法+问题+解决办法

    我从一个大神的GitHub那下载了一个安全卫士软件 https://github.com/kotlindev/MobileSafe 1.下载到自己Android的项目文件夹,解压. 2.用AS打开这个 ...

  8. 让我们写一个 Win32 文本编辑器吧 - 2. 计划和显示

    让我们写一个 Win32 文本编辑器吧 - 2. 计划和显示 如果你已经阅读了简介,相信你已经对我们接下来要做的事情有所了解. 本文,将会把简介中基础程序修改为一个窗体应用程序.并对编辑器接下来的编辑 ...

  9. Python入门-第一行代码到多行代码

    不管学啥语言,开始的第一行代码都是: print("hello word") 回车之后,就代表你正式进入代码的世界! 如果报错,恭喜你获得第一个书写bug,请检查单词拼写,双引号, ...

  10. 序列化和反序列化为什么要实现Serializable接口?(史上最全、简单易懂)

    目录结 前言 1.什么是序列化和反序列化 2.什么时候需要进行序列化和反序列化 2.1.服务器和浏览器交互时用到了Serializable接口吗? 2.2.Mybatis将数据持久化到数据库中用到了S ...