最大子数组和问题

  这篇文章不好 ! 请移步  http://blog.csdn.net/xjm199/article/details/17953753 

  不过关于动态规划有一篇文章特别好 , 漫画:什么是动态规划?(分享自知乎网)点击打开链接


动态规划(dynamic programing)

         通过组合子问题的解而解决整个问题的。这里Programming 翻译写成规划而不 是编程。维基百科上写到 This is  also usually done in a tublar form by iteratively genereting solutions to bigger and bigger subprobleams by using the solutions to small subprobleams. 说明动态规划的关键是子问题,而且动态规划的子问题是相互关联的。而分治算法是将问题分成相互独立的子问题,递归解决所有的子问题。 然后合并子问题会做很多不必要的工作,即重复的求解公共子问题。

动态规划对每个子问题都求解一遍,并且将其结果保存在表中,从而避免了子问题被重复计算。


适用范围

1. 动态规划问题通常情况下应用于最优化问题,这类问题一般都有多个可行的解,每个解有一个值,而我们希望从中找到最优的答案。

2. 该问题必须符合无后效性。即当前状态是历史的完全总结,某阶段的状态一旦确定,则此后过程的演变不再受此前各种状态及决策的影响,简单的说,就是“未来与过去无关”,当前的状态是此前历史的一个完整总结,此前的历史只能通过当前的状态去影响过程未来的演变。具体地说,如果一个问题被划分各个阶段之后,阶段I中的状态只能由阶段I-1中的状态通过状态转移方程得来,与其它状态没有关系,特别是与未发生的状态没有关系。


     简单动态规划问题

题目  最大子数组和问题

一个有N个整数元素的一个数组(A[0],A[1],.........A[N]),这个数组当然有很多子数组,那么数组之和的最大值是什么呢??   这是一道很简单的题目,暴力搜索的时间复杂度为O(N^2)。

例有数组 int A[5] = {-1, 2, 3, -4, 2};

符合条件的子数组为  2,3  即答案为 5;
再明确一下题意
1.子数组必须是连续的。
2.返回子数组的具体位置。
3.数组中包含:正整数,零,负整数。
例如
数组: {1, -2, 3, 5, -3, 2}   返回值为 8
数组: {0, -2, 3, 5, -1, 2}   返回值为 9
数组: {-9, -2, -3, -5, -6}   返回值为 -2  注意子数组不能为空
首先我们看看最直接的穷举法

int MaxSubString(int* A, int n)
{
  int max = min;  //初始值为负无穷大
  int sum;
  for(int i = 0; i < n; i++)
  {
    sum = 0;
    for(int j = i; j < n; j++)
    {
      sum += A[j];
      if(sum > max)
        max = sum;
    }
  }
  return max;
}


这种方法最直接,当也是最耗时的,他的时间复杂度为O(n^2);
问题分析
可以优化吗?答案是肯定的,可以考虑数组的第一个元素,以及最大的一段数组(A[i], ..., A[j]),和A[0]的关系,有一下几种情况:
1. 当0 = i = j 时,元素A[0]本身构成和最大的一段
2. 当0 = i < j 时,和最大的一段以A[0]开始;
3. 当0 < i 时, 元素A[0]和最大的一段没有关系。

从上面3中情况可以看出。可以将一个大问题(N个元素数组)转化为一个较小的问题(N-1个元素的数组)。假设已经知道(A[1], ...,A[n-1])中和最大的一段数组之和为All[1],并且已经知道
(A[1],...,A[n-1])中包含A[1]的和最大的一段数组为Start[1]。那么不难看出 (A[0], ..., A[n])中问题的解All[0] = max{ A[0], A[0] + start[1], All[1] }。通过这样的分析,可以看出这个问题
无有效性,可以用动态规划来解决。
解决方案

#include <iostream>
using namespace std; 
int max(int a, int b) {
if (a >= b) return a;
else  return b;
}

int  MaxAdd(int *A, int n){
int end = A[1];
int All = A[1];
for (int i = 2; i <= n; i++)
{  
end = max(A[i], end + A[i]);
All = max(All, end);
}
return  All; 
}

int main() {
int n, A[2000]; 
cin >> n; 
for (int i = 1; i <= n; i++)
{
cin >> A[i]; 
}
   cout<<MaxAdd(A, n)<<endl; 
}



我们通过动规算法解决该问题不仅效率很高(时间复杂度为O(n)),而且极其简便。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值