问题描述:

         给定整数A1, A2,……AN (可能有负数),求I到j的最大值。

例如:

         -2, 11, -4, 13, -5, -2时答案为20

  对于这个问题的算法有很多,当然我要说的是使用“动态规划”算法实现的程序,对于这个算法,我可以说很多人都曾经想到,但是没有想全(因为我就是这样的)。还有一点对于这个问题的动态规划的解法是非常经典的,她的时间复杂度是O(n),也就是线性的。而对于穷举法它的时间复杂度可是O(n3), 这样看来可以巨大的改进了。

  考虑这样的一个问题,我们从最简单的左边开始看,就如上面的例子,-2对于结果有影响吗?回答是没有。那么让我们看下面这样一个例子:

         6, -7, ……

         此时,我们还需要考虑6 和 –7 吗,有些人说要的,因为可能对于6,后面没有比其更大的了,是啊。问题是这样的。那么对于后面的结果分析其有影响吗?这个时候我们可以说没有影响的!

         到现在,上面是不是大家多曾经想到了呢?呵呵,我曾经就想到了,那我们为什么不把这问题,推倒后面呢?动态规划法就是解决这样的一个问题,我们知道此时前面的两个数就是一种最优的子结构(尽管只有2个数,不过是完全可以推广的。)

         书中的算法就告诉我们是如何推广的,我写这样的一篇文章的具体目的也就是为了说明以上的问题,因为我和大家一样都曾经想到了前面的算法,却没有考虑下去。以此感慨!并遗憾!

         那么书中的算法是这样的:(看这个算法之前应该先知道这个问题的“分治法”的求解,这样更让你觉得,这个算法的完美之处。)

Int MaxSubsequenceSum(const int A[], int N)
{
int ThisSum, MaxSum, j;
ThisSum = MaxSum = 0;
For(j=0; j < N; j++)
{
ThisSum += A[j];
If (ThisSum > MaxSum)
MaxSum = ThisSum;
Else if(ThisSum < 0)
ThisSum = 0;
}
return MaxSum;
}

对于这个算法的分析(逻辑):

  从左相右相加,若结果不断的增加,那么ThisSum将同MaxSum一起增加,如果遇到负数,那么也加到ThisSum上去,但是此时ThisSum < MaxSum,那么就不加。看ThisSum是不是会回升,若一直不回升,不断或是波浪型的下降,那么当它降到0时,说明前一段与后一段是可以抛弃的。正如有 7 , -8 一样,我们可以不要这两个数,但是我们知道MaxSum依然保存着前一段的最大值,(这就是这个算法中的厉害,我认为)。然后,ThisSum将从后面开始将这个子段进行分析,若有比当前MaxSum大的子段,然后替换(此时可以彻底抛弃前一段)。这样一趟扫描结果也就出来了。

后记:

         对于这个问题,一开始对于分治算法,我们可能很容易想对,而对与动态规划可能我们很难想到(至少我没有那么轻易就想到了)。尽管如此,还是比较庆幸想到了其最优子结构,问题解决到此,当然对于这个问题,我们还是可以用“分治”算法,其时间复杂度为:O(nlogn),也是比较优的,当然没有上面提到的优。

摘自:http://hi.baidu.com/longchengjiang/blog/item/7a5f2ad894a6d33733fa1c94%2Ehtml

补充:如果输入的所有整数为负,最大值为0.,原因是当子序列为空时,包含0个整数,也是子序列,它的和即为0,因为空子序列是连续的,所以总有一个连续子序列,它的和为0。(考虑空子序列的问题:空子序列也是子序列,它的和为0)

PS:MaxSum在这个算法中是一个中间变量,用来记录子问题的最值,而ThisSum是计算子问题的具体方法。

在网上搜到这篇,感觉讲得很通俗,易于理解。

下面附上此类问题的四种算法:

#include <iostream.h>
#include <stdio.h>
int MaxSubSum1( const int A[], int N);
int MaxSubSum2( const int A[], int N);
int MaxSubSum3( const int A[], int N);
int MaxSubSum4( const int A[], int N); const int M = 10; int main()
{
int B[M]; cout<< "请输入 " << M << " 个整数: "<< endl; for ( int i=0; i < M; i++ )
{
cin>> B[i];
} cout<< " 您输入的 " << M << " 个数为: "<< endl; for ( i = 0; i < M; i++ )
{
cout<< B[i] <<", ";
} cout<< " --------------------------------------- " << endl;
cout<< "四个函数的运算结果分别为:" << endl;
cout<< "-------------------------" << endl; cout<< MaxSubSum1( B, M ) << endl;
cout<< MaxSubSum2( B, M ) << endl;
cout<< MaxSubSum3( B, M ) << endl;
cout<< MaxSubSum4( B, M ) << endl; return 0;
} int MaxSubSum1( const int A[], int N) /* 第一种方法: 穷举 */
{
int ThisSum, MaxSum;
MaxSum = 0; for (int i=0; i < N; i++ )
{
for ( int j=i; j < N; j++ )
{
ThisSum = 0; for ( int k=i; k <= j; k++ )
{
ThisSum += A[k];
} if ( ThisSum > MaxSum )
{
MaxSum = ThisSum;
}
}
} return (MaxSum);
} int MaxSubSum2( const int A[], int N) /* 第二种方法: 分治 */
{
int ThisSum, MaxSum;
MaxSum = 0; for (int i=0; i < N; i++ )
{
ThisSum = 0; for ( int j=i; j < N; j++ )
{
ThisSum += A[j]; if ( ThisSum > MaxSum )
{
MaxSum = ThisSum;
}
}
} return (MaxSum);
} /* -----------------------------------------------------------------第三种方法: 二分法 */
static int BiMaxSubSum( const int A[], int Left, int Right ); int MaxSubSum3 ( const int A[], int N )
{
return BiMaxSubSum ( A, 0, N - 1 );
} static int BiMaxSubSum( const int A[], int Left, int Right )
{
int MaxSum, MaxLeftSum, MaxRightSum;
int LeftBorderSum, RightBorderSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int Center; if ( Left == Right )
{
if ( A[Left] > 0 )
{
return A[Left];
}
else
{
return 0;
} } Center = ( Left + Right ) / 2;
MaxLeftSum = BiMaxSubSum( A, Left, Center );
MaxRightSum = BiMaxSubSum( A, Center + 1, Right ); MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for ( int i = Center; i >= Left; i-- )
{
LeftBorderSum += A[i];
if ( LeftBorderSum > MaxLeftBorderSum )
{
MaxLeftBorderSum = LeftBorderSum;
}
} MaxRightBorderSum = 0;
RightBorderSum = 0;
for ( i = Center + 1; i <= Right; i++ )
{
RightBorderSum += A[i];
if ( RightBorderSum > MaxRightBorderSum )
{
MaxRightBorderSum = RightBorderSum;
}
} MaxSum = ( (MaxRightSum > MaxLeftSum ) ? MaxRightSum : MaxLeftSum );
int tmp = MaxRightBorderSum + MaxLeftBorderSum;
return ( ( MaxSum > tmp ) ? MaxSum : tmp );
} int MaxSubSum4( const int A[], int N) /* 第四种方法: */
{
int ThisSum, MaxSum;
ThisSum = MaxSum = 0; for (int i=0; i < N; i++ )
{
ThisSum += A[i]; if ( ThisSum > MaxSum )
{
MaxSum = ThisSum;
} else if ( ThisSum < 0 )
{
ThisSum = 0;
}
} return (MaxSum);
}

但是由于题目还要求 左右节点,,故法4修改如下

#include<iostream>
using namespace std;
int main()
{
int T,n;
int aq[100000];
while(cin>>T){
for(int k=1;k<=T;k++){
cin>>n;
for(int i=1;i<=n;i++)
cin>>aq[i];
int now=aq[1],sum=aq[1],left=1,right=1,oa=1;
for(int j=2;j<=n;j++){
if(now<0){now=aq[j];oa=j;}
else now+=aq[j]; if(now>=sum){
left=oa;
right=j;
sum=now;
} }
if(k!=1)cout<<endl;
cout<<"Case "<<k<<":"<<endl<<sum<<" "<<left<<" "<<right<<endl; }
}
return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

DP--HDU 1003(最大子串和)的更多相关文章

  1. hdu 1003 MAX SUM 简单的dp,测试样例之间输出空行

    测试样例之间输出空行,if(t>0) cout<<endl; 这样出最后一组测试样例之外,其它么每组测试样例之后都会输出一个空行. dp[i]表示以a[i]结尾的最大值,则:dp[i ...

  2. HDU 1003 Max Sum --- 经典DP

    HDU 1003    相关链接   HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...

  3. HDOJ(HDU).1003 Max Sum (DP)

    HDOJ(HDU).1003 Max Sum (DP) 点我挑战题目 算法学习-–动态规划初探 题意分析 给出一段数字序列,求出最大连续子段和.典型的动态规划问题. 用数组a表示存储的数字序列,sum ...

  4. dp 动态规划 hdu 1003 1087

    动态规划就是寻找最优解的过程 最重要的是找到关系式 hdu 1003 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1003 题目大意:求最大字序列和, ...

  5. hdu 1003 hdu 1231 最大连续子序列【dp】

    HDU1003 HDU1231 题意自明.可能是真的进步了点,记得刚开始研究这个问题时还想了好长时间,hdu 1231还手推了很长时间,今天重新写干净利落就AC了. #include<iostr ...

  6. 【ToReadList】六种姿势拿下连续子序列最大和问题,附伪代码(以HDU 1003 1231为例)(转载)

    问题描述:       连续子序列最大和,其实就是求一个序列中连续的子序列中元素和最大的那个. 比如例如给定序列: { -2, 11, -4, 13, -5, -2 } 其最大连续子序列为{ 11, ...

  7. poj1159 dp最长公共子串

    //Accepted 204 KB 891 ms //dp最长公共子串 //dp[i][j]=max(dp[i-1][j],dp[i][j-1]) //dp[i][j]=max(dp[i][j],dp ...

  8. HDU 1003(A - 最大子段和)

    HDU   1003(A - 最大子段和) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87125#problem/A 题目: ...

  9. [DP]最长公共子串

    题目 给定两个字符串str1和str2, 长度分别稳M和N,返回两个字符串的最长公共子串 解法一 这是一道经典的动态规划题,可以用M*N的二维dp数组求解.dp[i][j]代表以str1[i]和str ...

  10. fwt优化+树形DP HDU 5909

    //fwt优化+树形DP HDU 5909 //见官方题解 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ #include <bits/ ...

随机推荐

  1. 购物车业务逻辑(vuex)

    list(列表页): 1:发送ajax请求,获取相应的数据 2:给每一个上平添加一个点击事件 3:每一个商品都要有一个ID 4:当点击商品时,将商品id值传递给详情页 details(详情页): 1: ...

  2. Go语言 异常panic和恢复recover用法

    Go语言 异常panic和恢复recover用法 背景:Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在 ...

  3. cocos2d-x安装

    mac 安装2.2.6为例 1.进入cocos2d-x/tools/project-creator/ 2.输入 python create_project.py -project HelloWorld ...

  4. css3动画性能优化--针对移动端卡顿问题

    一.使用css,jquery,canvas制作动画 1.Canvas 优点:性能好,强大,支持多数浏览器(除了IE6.IE7.IE8),画出来的图形可以直接保存为 .png 或者 .jpg的图形: 缺 ...

  5. SAP BDC 交货增强无法进入

    最近碰到一个问题,使用BDC MODE 'N' UPDATE 'S' 无法进入增强: FV50XF0B_DELIVERY_PUBLISH DELIVERY_PUBLISH_AFTER_SAVE 前台操 ...

  6. asp.net页面刷新或者回发后DIV的滚动条位置不变!(转)

    源文件:http://www.cnblogs.com/nyth/archive/2011/06/10/2077868.html 当把数据放在div里面,然后给div设置Scroll显示,在页面刷新后或 ...

  7. 20155233 2016-2017-2 《Java程序设计》第1周学习总结

    20155233 2016-2017-2 <Java程序设计>第1周学习总结 教材学习内容总结 本周主要学习教材的第一章.第二章,了解了Java的发展历程,最基本的Java环境的搭建,以及 ...

  8. 20155305乔磊2016-2017-2《Java程序设计》第一周学习总结

    学习考核方式后感 老师对于成绩的获得有很多细节的地方,获得高分很不容易,考核次数也很多,100分分为课堂考核,实验,团队项目,老师对我们的要求可以说非常的严格,我也为有一个要求严格的老师感到幸运荣幸. ...

  9. PostgreSQL参数学习:max_wal_senders

    磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面:PostgreSQL基础知识与基本操作索引页    回到顶级页面:PostgreSQL索引页[作者 高健@博客园  luckyjackgao@g ...

  10. Java 中的正则(Pattern)

    /**String 中 replaceAll(),matches(),split() 等方法,都是调用Pattern中的方法.学习了,瞬间觉得Pattern强大了 public String repl ...