Problem Description
给定n(1<=n<=100000)个整数(可能为负数)组成的序列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。
注意:本题目要求用动态规划法求解,只需要输出最大子段和的值。
Input
第一行输入整数n(1<=n<=100000),表示整数序列中的数据元素个数;
第二行依次输入n个整数,对应顺序表中存放的每个数据元素值。
Output
输出所求的最大子段和
Sample Input
6
-2 11 -4 13 -5 -2
Sample Output
20
题解:
求最大子段和的动态规划法即在线算法利用的是如果某个小子段的子段和是最大的那么这个子段和必定大于0,如果从头开始累加,找最大子段和的过程中找到了比较大的值就把这个值保存下来,但是如果在某一步时出现了子段和小于0,那么目前所累加到的小子段不是我们要找的那个具有最大和的子段,应该放弃这个子段,从0开始,再进行累加,找到大的值保存下来,碰到小于0时再从0开始,再进行累加······直到走到序列的末尾,此时保存下来的最大值即为最大子段和。
参考代码一:
#include <stdio.h>
#include <stdlib.h>
int a[110000];
int zaixian(int a[],int n)
{
int i,s=0,max=0;
for(i=0; i<n; i++)//从头开始寻找
{
s=s+a[i];//开始累加
if(s>max)max=s;//如果找到一个比较大的值就把它保存下来
else if(s<0)s=0;//如果累加到小于0,说明这个子段不是存在最大子段和的子段,放弃该子段,从0开始,再进行寻找
}
return max;
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=0; i<n; i++)scanf("%d",&a[i]);
printf("%d\n",zaixian(a,n));
return 0;
}
参考代码二:
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
using namespace std;
#define List 110000
#define overflow -1
#define ok 1
typedef struct
{
ElemType *elem;
int length;
int listsize;
} sqlist;
int InitList(sqlist &L)
{
L.elem=(ElemType*)malloc(List*sizeof(ElemType));
if(!L.elem)exit(overflow);
L.length=0;
L.listsize=List;
return ok;
}
void charu(sqlist &L,int n)
{
int i;
for(i=0; i<n; i++)
{
scanf("%d",&L.elem[i]);
}
L.length=n;
}
int zaixian(sqlist &L,int n)
{
int i,s=0,max=0;
for(i=0; i<n; i++)
{
s=s+L.elem[i];
if(s>max)max=s;
else if(s<0)s=0;
}
return max;
}
int main()
{
int n,t;
sqlist L;
scanf("%d",&n);
InitList(L);
charu(L,n);
t=zaixian(L,n);
printf("%d\n",t);
return 0;
}