最大连续子段和
定义
给定n个整数(可能为负数)组成的序列a[1…n],求该序列中形如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的数字均为0的时候,最大子段和定义为0。
方法一:
在不考虑时间的情况下,使用循环暴力的方法,求出序列的所有子段和。该方法会有3层循环嵌套。时间复杂度为O(n^3)。
#include <cstdio>
#include <algorithm>
#define maxn 1000
using namespace std;
int sum[maxn][maxn]={0}; //sum[i][j]表示从i到j的元素之和
int main()
{
int a[maxn];
int n; //元素的个数
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
for(int k=i;k<=j;k++)
sum[i][j] += a[k];
int _max = -50000;
for(int x=0;x<n;x++)
for(int y=x;y<n;y++)
if(sum[x][y] > _max)
_max = sum[x][y];
printf("%d\n",_max);
return 0;
}
在初始化 _max的时候,应该使 _max的值小于最小数据。如果只是说明为int类型,可以初始化为INT _MIN。
方法二:
在方法一的基础上sum[i][j] = Tsum[j] - Tsum[i-1]。
方法三:
利用动态规划。时间复杂度为O(n)。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
int n,T,number;
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
int max = INT_MIN;
long long sum = 0;
int begin = 0,end = 0 ,add = 1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&number);
sum += number;
if(sum > max)
{
max = sum;
begin = add;
end = i;
}
if(sum <0)
{
sum = 0;
add = i+1;
}
}
printf("Case %d:\n",t);
printf("%d %d %d\n",max,begin,end);
if(t<T)
printf("\n");
}
return 0;
}
如果前n-1项和为整数,因为是连续项的和,所以只有2种选择,加上第n项(即使第n项为负数),或者舍弃前n-1项,第n项起构成新的连续子段。若前n-1项的和是负的,那么应该舍弃,使n项构成新的子段。若前n-1项是正的,那么即使第n项是负的也应该进行选择1。_max要始终更新为最大的数。