1.题目描述
2.算法思想
方法1:枚举
将所有的(i,j)对找出来,计算对应子段和,最后得到最大的。
int MaxSum(int*a ,int *besti,int &bestj){
int sum=0,T;
for(int i=1;i<=n;i++)
for(int j=i;i<=n;j++){
T=0;
for(int k=i;k<=j;k++)
T+=a[j];
if(T>sum){
sum=T;*besti=i;*bestj=j;
}
}
}
优化:
int MaxSum(int*a ,int *besti,int &bestj){
int sum=0,T;
for(int i=1;i<=n;i++)
T=0;
for(int j=i;i<=n;j++){
T+=a[j];
if(T>sum){
sum=T;*besti=i;*bestj=j;
}
}
}
方法二:分治
①划分为左右两半a【1:n/2】 a【n/2+1:n】
②求a【1:n/2】 a【n/2+1:n】的最大子段和
③合并**:计算跨界的子段和**,与a【1:n/2】 a【n/2+1:n】的比较,取最大的。
T(n)=2T(n/2)+O(n)= O(nlogn)
第三种跨界的情况?
i: n/2->1
j: n/2+1->n
int s1=0,lefts=0;
for(int i=mid;i>L;i--){
lefts+=a[i];
if(lefts>s1) s1=lefts;
}
int s2=0,rights=0;
for(int i=mid+1;i<R;i++){
rights+=a[i];
if(rights>s2) s2=rights;
}
总体:
int MaxSubSum(int *a, int left, int right) {
int
sum= 0;
if (1eft == right)
sum = a[1eft]>0 ? a[1eft] : 0;
else {
int center = (1eft+right)/2;
int leftsum = MaxSubSum(a, 1eft, center);
int rightsum = MaxSubSum(a, center+1, right);
int s1=0,lefts=0;
for(int i=mid;i>L;i--){
lefts+=a[i];
if(lefts>s1) s1=lefts;
}
int s2=0,rights=0;
for(int i=mid+1;i<R;i++){
rights+=a[i];
if(rights>s2) s2=rights;
}
sum = 51+s2;
if (sum < leftsum)
sum = leftsum;
if (sum < rightsum)
sum = rightsum;
}
return sum;
}
}
方法三:动态规划法
(1)最优子结构:
分析:
①( i , j )是和最大的子段,则( i , j ) 是以 j 为右端点的子段中和最大的。
②子问题:以 j ( 1<=j<=n ) 为右端点的最大子段和b[j]。
③原问题 = max { b[1] , b[2], ……b[n] }
(2)状态转移方程:
b[j] = b[j-1]>0? b[j-1]+a[j] : a[j];
int MaxSum(int *a, int n){
int sum=0,b=0;
for( int j=1 ; j<=n; j++ ){
b = b>0 ? b+a[j]:a[j];
if( b> sum ) b=sum;
}
return sum;
}