1. 给定N个整数的序列{ A1, A2, …, AN},其中可能有正数也可能有负数,找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大,如果是负数,则返回0。使用下列函数,完成分治法求最大子列和。
算法一,穷举法T( N ) = O( N3 )
思想:算法思想:算出每个子序列的和,即算出序列中第i个到第j个数的和(j>=i),并进行比较
int MaxSubseqSum1( int A[], int N )
{ int ThisSum, MaxSum = 0;
int i, j, k;
for( i = 0; i < N; i++ ) { /* i是子列左端位置*/
for( j = i; j < N; j++ ) { /* j是子列右端位置*/
ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和*/
for( k = i; k <= j; k++ )
ThisSum += A[k];
if( ThisSum > MaxSum ) /* 如果刚得到的这个子列和更大*/
MaxSum = ThisSum; /* 则更新结果*/
} /* j循环结束*/
} /* i循环结束*/
return MaxSum;
算法二T( N ) = O( N2 )
对上一个算法的改进,减少重复计算
int MaxSubseqSum2( int A[], int N )
{ int ThisSum, MaxSum = 0;
int i, j;
for( i = 0; i < N; i++ ) { /* i是子列左端位置*/
ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和*/
for( j = i; j < N; j++ ) { /* j是子列右端位置*/
ThisSum += A[j];
/*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
if( ThisSum > MaxSum ) /* 如果刚得到的这个子列和更大*/
MaxSum = ThisSum; /* 则更新结果*/
} /* j循环结束*/
} /* i循环结束*/
return MaxSum;
}
算法三:分而治之
T ( N ) =O( N log N )
int MaxSum(int a[],int left,int right);
int threeOfMax(int a1,int a2,int a3);
int centerMaxSum(int a[],int left,int right);
#include<stdio.h>
#define N 50
int MaxSum(int a[],int left,int right);
int centerMaxSum(int a[],int left,int right);
int threeOfMax(int a1,int a2,int a3);
int main(){
int n;
int a[N];
printf("请设置数组位数n:\n");
scanf("%d",&n);
printf("请输入数值:\n");
for(int i = 0;i<n;i++){
scanf("%d",&a[i]);
}
int left=0;
int right=n-1;
int maxSubSum = MaxSum(a,left,right);
printf("最大子序列的和为:%d\n",maxSubSum);
return 0;
}
int MaxSum(int a[],int left,int right){
int a1,a2,a3,i;
int MaxLeftSum, MaxRightSum; //存放左右子问题的解
int MaxLeftBorderSum, MaxRightBorderSum; //存放跨分界线的结果
int LeftBorderSum, RightBorderSum;
// 递归终止条件 直到分到最后一个元素
if(left==right){
if( a[left] > 0 )
return a[left];
else
return 0;
}
int mid = (left+right)/2;
// 划分左边
a1 = MaxSum(a,left,mid);
// 划分右边
a2 = MaxSum(a,mid+1,right);
// 求解s3
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for( i=mid; i>=left; i-- ) //从中线向左扫描
{
LeftBorderSum += a[i];
if( LeftBorderSum > MaxLeftBorderSum )
MaxLeftBorderSum = LeftBorderSum;
} //左边扫描结束
MaxRightBorderSum = 0;
RightBorderSum = 0;
for( i=mid+1; i<=right; i++ ) //从中线向右扫描
{
RightBorderSum += a[i];
if( RightBorderSum > MaxRightBorderSum )
MaxRightBorderSum = RightBorderSum;
} //右边扫描结束
a3 =centerMaxSum(a,left,right);;
//下面返回"治"的结果
return threeOfMax( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
}
// 求解s3
int centerMaxSum(int a[],int left,int right){
int leftSum = 0;
int rightSum = 0;
int templeftSum = 0;
int temprightSum = 0;
int mid=(left+right)/2;
for(int i = mid;i>=left;i--){
templeftSum = templeftSum+a[i];
if(templeftSum>leftSum)
leftSum=templeftSum;
}
for(int j = mid+1;j<=right;j++){
temprightSum = temprightSum+a[j];
if(temprightSum>rightSum)
rightSum=temprightSum;
}
return leftSum+rightSum;
}
// 求解最大的子列和
int threeOfMax(int a1,int a2,int a3){
int maxSum = a1>a2?a1:a2;
return maxSum>a3?maxSum:a3;
}
算法四在线处理T( N ) = O( N)
设a[i]为和最大序列的起点,则如果a[i]是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]作为起点的子序列都可以通过a[i+1]作起点而得到改进。
int MaxSubseqSum4( int A[], int N )
{ int ThisSum, MaxSum;
int i;
ThisSum = MaxSum = 0;
for( i = 0; i < N; i++ ) {
ThisSum += A[i]; /* 向右累加*/
if( ThisSum > MaxSum )
MaxSum = ThisSum; /* 发现更大和则更新当前结果*/
else if( ThisSum < 0 ) /* 如果当前子列和为负*/
ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之*/
}
return MaxSum;