最大子数组问题(动态规划)

题目描述如下:
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。

要求算法的时间复杂度为O(n)。

输入格式:
输入有两行:

第一行是n值(1<=n<=10000);

第二行是n个整数。

输出格式:
输出最大子段和。

输入样例:
在这里给出一组输入。例如:

6
-2 11 -4 13 -5 -2

输出样例:
在这里给出相应的输出。例如:

20
解析:这是一道典型的动态规划问题,动态规划是当前所要解决的问题依赖于它前面的子问题,所以我们要先把子问题求解出来,才能够解决当前问题,这也就决定着我们的思路是先求解最小的子问题,自低向上的递推,直到解决问题
具体的分析已经写到注释中

#include<stdio.h>
#define MAX 1002
int main(){
    int n,a[MAX];
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
//--------D[i]表示的是以a[i]为终止位置的最优解-------

    int D[n],max=a[0];//max=a[0]很关键,它和第18行选出最大的有关系,要不然的话,第18行只是从a[1]~a[n-1]选出最大的
    D[0]=a[0];//第一个数字前面没有数字 所以以a[0]为终止位置的最优解就是它自己
    for(int i=1;i<n;i++){//每一个数字都找到以它为终止位置的最优解
        if(D[i-1]>0)/*如果a[i]前面的那个数字的最优解大于0,那么再加上a[i]得D[i],则D[i]就是以a[i]结
        尾的所有可能中的最优解*/
            D[i]=a[i]+D[i-1];
        else
            D[i]=a[i];/*如果a[i]前面的那个数字的最优解小于0,那么以a[i]结尾的所有可能中的最优解就是它本身*/
        if(D[i]>max)
            max=D[i];//选出最大的
    }
    for(int i=0;i<n;i++)//输出结果
        printf("%d ",D[i]);
    printf("\nmax is %d\n",max);

//--------D[i]表示的是以a[i]为起始位置的最优解------

    D[n-1]=a[n-1];
    max=a[0];
    for(int i=n-2;i>=0;i--){
        if(D[i+1]>0)
            D[i]=a[i]+D[i+1];
        else
            D[i]=a[i];
        if(D[i]>max)
            max=D[i];
    }
    for(int i=0;i<n;i++)
        printf("%d ",D[i]);
    printf("\nmax is %d\n",max);

//不需要数组,用一个变量temp保存a[i]前面的以a[i-1]为终止最优解,这是第一种方法的简洁版
    int temp=0;
    max=a[0];
    for(int i=0;i<n;i++){
        if(temp>0)
            temp+=a[i];
        else
            temp=a[i];
        if(temp>max)
            max=temp;
    }
    printf("max is %d\n",max);
    return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值