最大子段和-分治&&动态规划

 

 

   N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值。当所给的整数均为负数时和为0。

例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。

Input

第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)

Output

输出最大子段和。

Input 示例

6
-2
11
-4
13
-5
-2

Output 示例

20
// 1.穷举50000显然超时,时间复杂度为O(n^2).
#include<iostream>
#include<cstdio>
using namespace std;
int a[50005];
int main()
{
   int i,j,n;
   while(~scanf("%d",&n))
   {
        for(i=0;i<n;i++)
            scanf("%d",a+i);
            __int64 max=0;
            for(i=0;i<n;i++)
            {
                __int64 sum=0;
                for(j=i;j<n;j++)
                {
                    sum+=a[j];
                    if(sum>max)
                        max=sum;
                }
            }
        printf("%I64d\n",max);
   }
    return 0;
}
/* 2.分治法  时间复杂度为O(nlogn).

求子区间及最大和,从结构上是非常适合分治法的,因为所有子区间[start, end]只可能有以下三种可能性:

在[1, n/2]这个区域内

在[n/2+1, n]这个区域内

起点位于[1,n/2],终点位于[n/2+1,n]内

以上三种情形的最大者,即为所求. 前两种情形符合子问题递归特性,所以递归可以求出. 对于第三种情形,则需要单独处理.

第三种情形必然包括了n/2和n/2+1两个位置,这样就可以利用第二种穷举的思路求出:

以n/2为终点,往左移动扩张,求出和最大的一个left_max

以n/2+1为起点,往右移动扩张,求出和最大的一个right_max

left_max+right_max是第三种情况可能的最大值

*/

#include<iostream>
#include<cstdio>
using namespace std;
int a[50005];
__int64 maxInterval(int *a,int l,int r)
{
    if(l==r)
        return a[l]>0?a[l]:0;
    int mid=(l+r)/2;
    __int64 leftmaxInterval=maxInterval(a,l,mid);
    __int64 rightmaxInterval=maxInterval(a,mid+1,r);
    int i;
    __int64 sum=0;
    __int64 left_max=0;
    for(i=mid;i>=l;i--)
    {
        sum+=a[i];
        if(sum>left_max)
            left_max=sum;
    }
    sum=0;
    __int64 right_max=0;
    for(i=mid+1;i<=r;i++)
    {
        sum+=a[i];
        if(sum>right_max)
            right_max=sum;
    }
    __int64 ans=left_max+right_max;
    if(leftmaxInterval>ans)
        ans=leftmaxInterval;
    if(rightmaxInterval>ans)
        ans=rightmaxInterval;
    return ans;
}
int main()
{
   int i,j,n;
   while(~scanf("%d",&n))
   {
        for(i=0;i<n;i++)
            scanf("%d",a+i);
        printf("%I64d\n",maxInterval(a,0,n-1));
   }
    return 0;
}

/* 3.动态规划法 计算时间复杂度为O(n),是最优的解

令b[j]表示以位置 j 为终点的所有子区间中和最大的一个

子问题:如j为终点的最大子区间包含了位置j-1,则以j-1为终点的最大子区间必然包括在其中

如果b[j-1] >0, 那么显然b[j] = b[j-1] + a[j],用之前最大的一个加上a[j]即可,因为a[j]必须包含

如果b[j-1]<=0,那么b[j] = a[j] ,因为既然最大,前面的负数必然不能使你更大

*/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[50005];
__int64 b[50006];
int main()
{
   // freopen("1.txt","r",stdin);
    __int64 max;
    int i,n,flag;
    while(~scanf("%d",&n))
    {
        flag=0;
        max=0;
        for(i=1; i<=n; i++)
        {
            scanf("%d",a+i);
            if(a[i]>0)
                flag=1;
        }
        memset(b,0,n+1);
        for(i=1; i<=n; ++i)
        {
            if(b[i-1]>0)
                b[i]=b[i-1]+a[i];
            else
                b[i]=a[i];
            if(b[i]>max)
                max=b[i];
        }
        if(flag)
            printf("%I64d\n",max);
        else
            puts("0");
    }
    return 0;
}

 

时间: 2024-12-03 06:13:42

最大子段和-分治&amp;&amp;动态规划的相关文章

动态规划-一个老问题,最大子段和

问题描述 一个老问题,最大子段和 动态规划算法如下: MaxSbuSum(int n,int a[]) { int sum=0,b=0; for j=1 to n do { b+=a[j]; if(b<0) b=0; if(b>sum) sum=b: } return sum } 这样可以求出最大子段和,现在想同时求出最大子段和的区间,该怎么添加代码呢? 解决方案 最大子段和问题最大子段问题 分治算法最大子段和问题 解决方案二: 记录一下当前区间,如果多个最大的话,可以两遍扫描,保存每次的最大

畅销榜上的机器学习、深度学习书单!

机器学习是一门多领域交叉学科,涉及概率论.统计学.逼近论.凸分析.算法复杂度等多门学科,专门研究计算机怎样模拟或实现人类的学习行为.机器学习是人工智能的核心,是使计算机具有智能的根本途径. 近年来,机器学习领域受到越来越多的关注,相关的机器学习算法开始成为热点,知乎上同类问题同样不少,如机器学习该怎么入门?机器学习.数据挖掘 如何进阶成为大神?普通程序员如何向人工智能靠拢?学习人工智能该看什么书? 今天小编整理了一些机器学习.深度学习.人工智能相关图书,涉及到的关键词如下:深度学习.Tensor

Java高级软件工程师面试考纲

当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题, 很多也是着重在Java语言基础上.实际上,如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网 络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人.

IT人的算法书单:挖掘程序的灵魂

我们都知道对于软件而言,最为经典的定义就是程序=算法+数据结构,算法对于软件的重要性不言而喻,甚至可以说算法是程序的灵魂所在.甚至有人说如果计算机系只开设三门课的话,那么一定是:离散数学.编译原理还有算法和数据结构.算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.其实对于IT人而言,无时无刻都沉浸在算法之中,小到可能只是对于一个简单的一维数组进行排序,大到使用进行实时个性化推荐或者使用机器学习算法预测未来的发展趋

动态规划算法--蛮力算法求最大子段和

问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的子段和的最大值.当所给的整均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+-+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20. 最大子段和是动态规划中的一种. 当b[j-1]>0时b[j]=

算法洗脑系列(8篇)——第七篇 动态规划

     今天跟大家分享下算法思想中比较难的一种"动态规划",动态规划给人像是作战时常用的"迂回战术",或者说是 游击战,在运动中寻找突破口.   一: 思想    首先要了解"动态规划",必须先知道什么叫做"多阶段决策",百科里面对这个问题解释的很全,我就load一段出来, 大家得要好好品味,好好分析.   上面图中最后一句话就定义了动态规划是要干什么的问题.   二:使用规则     现在我们知道动态规划要解决啥问题了,那

动态规划与递归联系。

问题描述 动态规划与递归联系. 求教各位,以前一直觉得动态规划就是对递归的优化,最近发现并不是.我想请问各位动态规划和递归之间有什么联系吗?还是说动态规划和递归没关系. 解决方案 动态规划和递归毫无关系,事实上也没有"递归优化"这种说法. 动态规划的思想是将要解决的问题转化为一系列逐步求解的问题并且逐步加以解决.动态规划避免了无意义的穷举,它强调逐步解决问题,让先前解决的结果可以作为后续解决问题的条件避免重复求解相同的问题. 举一个例子,最长公共子序列问题(我曾经解答过,完整代码在这里

poj 2479 最大连续子段和 dp算法

一.文章来由 晚上一水~~poj2479,一道简单的dp问题,回顾一下动态规划 二.求最大子段和 这道题是求一个序列中的两个子段的最大和,是求纯的最大和的一个变体,例如题目中给出的例子 1 -1 2 2 3 -3 4 -4 5 -5 In the sample, we choose {2,2,3,-3,4} and {5}, then we can get the answer. 答案是 13 如何求一个序列的子段和: int MaxSub (int a[],int N)//此为只需要求最大的和

《算法技术手册》一3.6.3 动态规划

3.6.3 动态规划 动态规划是分治算法的一个衍生,它将一个问题切分成多个更加简单的子问题,然后按照顺序逐个解决.对于每个子问题,它只求解一次,然后将结果存储起来以供后续使用,这样可以避免重复计算.此外,动态规划在计算当前解时,会结合较小规模的子问题的解,并且不断增加子问题的规模.很多情况下,最终计算出来的解即为全局最优解.动态规划常用于求解最值优化类问题上.下面通过一个示例来阐释动态规划算法.科学家经常通过比对DNA序列来确定其相似性.现有这样一个DNA序列--由A.C.T.G所组成.因此,一