Case 1:

14 1 4

Case 2:

7 1 6

题目的大致意思就是要你从给定的数组中找出一段连续的子序列,使得这段连续的子序列中所有数字的总和不小于数组中其他任何一段连续子序列中数字的总和。只有傻子(我QAQ)才会用暴力枚举的方法来做这题,必TLE。用分治法来做也是一种思路,不过我没试过,不知道会不会TLE。最好的方法就是动态规划。那么怎么做呢?

动态规划法其实在某种程度上也用的是枚举的思路,只不过枚举的方法比较巧妙而已。显然,不论是哪一段连续子序列都是有终点的(废话),我们可以依次把数组中每一个元素都看作是连续子序列的终点,把以该元素为终点的所有连续子序列找出来。这样就可以枚举出数组中所有的连续子序列。

例如,有一个数组,它所包含的元素依次是5,9,2,4。以第一个元素为终点的连续子序列有"5",以第二个元素为终点的连续子序列有"5,9","9",以第三个元素为终点的连续子序列有"5,9,2","9,2","2",以第四个元素为终点的连续子序列有"5,9,2,4","9,2,4","2,4","4"。于是以上找到的所有的连续子序列即为该数组中的所有连续子序列。

“讲了半天,你这不还是暴力枚举嘛......" 我们当然不是要以这种方式来暴力枚举,而是要通过这样一种思路,找到其中的递推关系。既然现在我们是通过终点来寻找连续子序列的话,那么就定义一个函数dp(i):以数组中第i个元素作为终点,找出所有以第i个元素为终点的连续子序列,并依次求出这些连续子序列中所有元素的总和,所有总和中的最大值即为dp(i)的值。

例如,一个数组中的元素有1,-2,4,3。以第3个元素,也就是4,作为终点,找出所有以它为终点的连续子序列:"1,-2,4","-2,4","4"。序列"1,-2,4"的所有元素总和为3,序列"-2,4"的所有元素总和为2,序列"4”的所有元素总和为4。而4>3>2,则4为所有总和中的最大值,于是dp(3)=4。

相信你已经明白了这里定义的函数dp(i)的含义了。那么如何找到这个函数的递推关系呢?

说到递推关系,首先当然要明确递推的起点。显然dp(1)的值就是数组中的第一个元素,这就是递推的起点。接下来就只需要找到dp(i - 1)与dp(i)之间的关系,我们就可以求出dp(1),dp(2), ...... ,dp(i), ...... ,dp(n)了。很容易就可以知道,当dp(i - 1) >= 0时,dp(i) = dp(i - 1) + arr[i](arr[i]表示数组中第i个元素);当dp(i - 1) < 0时,dp(i) = arr[i]。

不过求出这些dp的值有什么用呢?刚才讲过,依次以数组中每个元素为终点,找出以这些元素为终点的所有连续子序列,就能够枚举出数组的所有连续子序列。而求出所有dp值的过程其实就相当于把所有连续子序列都枚举了一遍。既然已经找出了所有"局部"的最大值,那我们把这些"局部"的最大值合起来,找到"全局"的最大值,不就得到了问题的最终答案了嘛?所以,接下来我们要做的,就是从所有的dp值中,找出最大的那一个dp值,这个最大的dp值,就是元素总和最大的连续子序列。

终于把最关键的讲完了,接下来放出代码~这里先暂时只考虑求最大和的问题,所以只演示一个用来求最大和的函数,其他的后面再说。代码可能写得比较啰嗦,不过这是为了让大家容易看得明白。

1 #include

2 #include

3 #include

4 using namespacestd;5

6 int getMaxSum(int* arr,inthigh)7 {8 const int SIZE =1e4;9 int dp[SIZE] = {0};10

11 for(int i = 0;i <= high;++i)12 {13 if(i == 0)14 {15 dp[i] =arr[i];16 }17 else if(i > 0)18 {19 dp[i] = max(dp[i - 1] +arr[i],arr[i]);20 }21 }22

23 int maxSum =INT_MIN;24 for(int i = 0;i <= high;++i)25 {26 if(dp[i] >maxSum)27 {28 maxSum =dp[i];29 }30 }31

32 returnmaxSum;33 }

现在我们已经解决了如何求最大和的问题了,不过这道oj题还要求我们给出所求连续子序列的起点位置和终点位置。如果是用暴力枚举法的话,很容易就可以记录下起点位置和终点位置。不过如果是用动态规划法的话,想要记录下位置,可能还得稍微动一下脑子。不过也不难。我们自己手动模拟一下求dp值的过程,就可以找到其中的规律了。

下图是计算一个数组的所有dp值的过程。

仔细观察上图,就可以找到其中的规律:计算一个数组的所有dp值的过程,其实是一个"从头加到尾"的过程,只不过在dp值小于零的地方需要"断开"。具体地说,计算一个数组的所有dp值时,我们需要做的是从第一个元素开始,依次取数,把这些数一个一个加起来。如果当加到第i个数时所得到的和为一个负数,则把前面i个数的和直接"丢掉"不要,然后从第i + 1个数开始,再从零开始加,之后循环往复地重复上述步骤。于是,我们就可以以这样一种方法得到每个dp值对应的连续子序列的起点位置和终点位置:一开始把起点位置设为1,也就是整个数组的起点。显然,dp(1)的终点位置也是1。然后求后面的dp值时,只要dp(i - 1)的值是非负的,那么dp(i)对应的起点位置就是dp(i - 1)的起点位置,而终点位置就是dp(i - 1)的终点位置 + 1。如果dp(i - 1)的值是负数,则dp(i)对应的起点位置就应该是i,终点位置也是i。

也许会有人觉得需要另外开两个数组,保存每个dp值对应的起点位置和终点。但其实没必要。我们只需要在每求出一个dp值时,都去更新一下最大值和起点终点位置即可。具体的做法见下面的代码。

1 #include

2 #include

3

4 const int SIZE = 1e5 + 10;5 intarr[SIZE];6 intdp[SIZE];7

8 intmain()9 {10 int nCase = 0;11 scanf("%d",&nCase);12

13 for(int i = 1;i <= nCase;++i)14 {15 int n = 0;16 scanf("%d",&n);17 for(int j = 0;j < n;++j)18 {19 scanf("%d",&arr[j]);20 }21

22 int maxSum =INT_MIN;23 int mLow = 0; //和最大的连续子序列的下界

24 int mHigh = 0; //和最大的连续子序列的上界

25 int tLow = 0; //以第j个元素为结尾的和最大的连续子序列的下界

26 int tHigh = 0; //以第j个元素为结尾的和最大的连续子序列的上界

27 for(int j = 0;j < n;++j)28 {29 if(j == 0)30 {31 dp[j] =arr[j];32 tLow =j;33 tHigh =j;34 }35 else if(j > 0)36 {37 if(dp[j - 1] >= 0)38 {39 dp[j] = dp[j - 1] +arr[j];40 tHigh =j;41 }42 else if(dp[j - 1] < 0)43 {44 dp[j] =arr[j];45 tLow =j;46 tHigh =j;47 }48 }49

50 if(dp[j] >maxSum)51 {52 maxSum =dp[j];53 mLow =tLow;54 mHigh =tHigh;55 }56 }57

58 if(i ==nCase)59 {60 printf("Case %d:

%d %d %d",i,maxSum,mLow + 1,mHigh + 1);61 }62 else

63 {64 printf("Case %d:

%d %d %d",i,maxSum,mLow + 1,mHigh + 1);65 }66 }67 }

上面的代码就已经足够让这道oj题AC了。不过,其实上面的做法还不是最好的做法。我们其实没有必要开一个数组保存dp值。就像上面说过的,求dp值的过程其实就是"从头加到尾"的过程。我们只需要弄一个变量sum,从数组的第一个元素开始,一个一个取数加到sum中,每加一个数后都用sum去更新一下最大值。一旦sum的值为负数,就把sum重新置零,也就是把前面得到的总和"丢掉"不要,然后再从下一个数开始一个一个取数加到sum中......不断地重复这样的步骤即可。

下面的代码就是一种比较好的做法。

#include #include

intmain()

{int nCase = 0;

scanf("%d",&nCase);for(int i = 1;i <= nCase;++i)

{int n = 0;

scanf("%d",&n);int high = 0;int low = 0;int lowTemp = 1;int maxSum =INT_MIN;int sum = 0;int ele = 0;for(int j = 1;j <= n;++j)

{

scanf("%d",&ele);

sum+=ele;if(sum >maxSum)

{

maxSum=sum;

low=lowTemp;

high=j;

}if(sum < 0)

{

sum= 0;

lowTemp= j + 1;

}

}if(i ==nCase)

{

printf("Case %d:

%d %d %d",i,maxSum,low,high);

}else{

printf("Case %d:

%d %d %d",i,maxSum,low,high);

}

}

}

(完)

php 求最大连续子序列,[HDOJ 1003]动态规划法求和最大的连续子序列相关推荐

  1. 计算机算法设计与分析 动态规划 实验报告,动态规划法解最长公共子序列(计算机算法设计与分析实验报告).doc...

    动态规划法解最长公共子序列(计算机算法设计与分析实验报告) 实报 告 实验名称:任课教师::姓 名:完成日期:二.主要实验内容及要求: 要求按动态规划法原理求解问题: 要求交互输入两个序列数据: 要求 ...

  2. 求最长公共子序列python_用Python计算最长公共子序列和最长公共子串

    1. 什么是最长公共子序列?什么是最长公共子串? 1.1. 最长公共子序列(Longest-Common-Subsequences,LCS) 最长公共子序列(Longest-Common-Subseq ...

  3. Java_[排序子序列]牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的。

    链接:https://www.nowcoder.com/questionTerminal/2d3f6ddd82da445d804c95db22dcc471? 牛牛定义排序子序列为一个数组中一段连续的子 ...

  4. 函数在区间连续可以推出什么_A-22 函数的点连续、单侧连续、区间连续

    欢迎光临我的专栏<微积分学习之旅>,一起学习,共同提高. 有些函数在求 时的极限时,可以直接求函数在 时的取值,我们称具有这种特性函数" 在 点连续 ".我们将会看到, ...

  5. 输出最长单调递增子序列java_动态规划实现最长单调递增子序列

    1. 实验环境 操作系统:Mac 64 运行内存:16GB 编程语言:Java 编译环境:Eclipse 2. 题目要求 设计一个Ο(nlgn)时间的算法,求一个 n 个数的序列的最长单调递增子序列. ...

  6. HDOJ 2011 多项式求和 超详细

    HDOJ 2001 多项式求和 Problem Description 多项式的描述如下: 1 - 1/2 + 1/3 - 1/4 + 1/5 - 1/6 + ... 现在请你求出该多项式的前n项的和 ...

  7. JS密码校验规则前台验证(不能连续字符(如123、abc)连续3位或3位以上)(不能相同字符(如111、aaa)连续3位或3位以上)...

    密码必须为8到16位且必须包含数字和字母 密码必须包含特殊字符[_&#%] 不能连续字符(如123.abc)连续3位或3位以上 不能相同字符(如111.aaa)连续3位或3位以上 /*** 外 ...

  8. JS密码校验规则前台验证(不能连续字符(如123、abc)连续3位或3位以上)(不能相同字符(如111、aaa)连续3位或3位以上)

    密码必须为8到16位且必须包含数字和字母 密码必须包含特殊字符[_&#%] 不能连续字符(如123.abc)连续3位或3位以上 不能相同字符(如111.aaa)连续3位或3位以上 /*** 外 ...

  9. 《信息与编码》考试复习笔记6----第六章连续信源熵和信道容量(考点在连续信道容量)

    系列文章链接目录 一.<信息与编码>考试复习笔记1----第一章概论 二.<信息与编码>考试复习笔记2----第二章离散信息源 三.<信息与编码>考试复习笔记2-- ...

最新文章

  1. iPhone 中使用NSLocalizedString实现国际化
  2. 基于cropper和sweetalert的简单图片/头像裁剪上传
  3. 介绍50个 WordPress 动作挂钩
  4. Citrix 未注册解决办法
  5. 这谁写的技术文档?我想锤死他...
  6. 利用Quartz2D-contex绘制三角形
  7. haddler处理队列 netty_Netty堆外内存泄漏排查,这一篇全讲清楚了
  8. EnableDebugPriv;
  9. 什么是IP地址、子网掩码、路由和网关?
  10. 2010年IT行业十大收购
  11. 我的python之行
  12. 数据表--excel的读取案例
  13. C#:SQLite大量插入的效率问题
  14. 图片点击后出现模态框效果的实现
  15. 社会工程学部分攻击经典方法总结
  16. ADAS功能中LCA、LKA、LCK...区别
  17. Echarts x轴设置上下偏移
  18. 高仿Android网易云音乐OkHttp+Retrofit+RxJava+Glide+MVC+MVVM
  19. 英语单词记忆测试软件,适用于检查学生英语单词背诵情况的软件
  20. HBuilder开发旅游类APP(三) ----- 给APP添加底部导航栏(底部选项卡)

热门文章

  1. 全球土地利用/覆盖数据
  2. 如何映射网络驱动器?
  3. MFC中的CDC 绘图
  4. ambari Metrics Collector 无法收集信息
  5. ios 替换数组中元素_IOS中数组方法
  6. 【数据挖掘】之 数据挖掘 绪论
  7. 数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver
  8. Electron教程(七)结语
  9. 微信小程序云开发查询数据库结果为空
  10. 可观测宇宙中,我们可能是唯一的生命