#include <stdio.h>
#include <math.h>
#include <time.h>
#define MAXK 1e7
clock_t start,stop;
double duration;
/*一种复杂度为O(n^3)的暴力解法*/
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; //则更新结果
}
}
return MaxSum;
}
/*复杂度为O(n^2)的算法*/
int MaxSubseqSum2(int A[],int N)
{
int ThisSum,MaxSum=0;
int i,j;
for(i=0;i<N;i++){
ThisSum=0; //ThisSum是从A[i]到A[j]的子列和
for(j=i;j<N;j++){
//对于相同的i,不同的j,只要在j-1次循环的基础上累加一项即可
ThisSum +=A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
}
}
return MaxSum;
}
/*分而治之算法,复杂度为O(NlogN)*/
int Max3( int A, int B, int C )
{ //返回3个整数中的最大值
return A > B ? A > C ? A : C : B > C ? B : C;
}
int DivideAndConquer( int List[], int left, int right )
{ //分治法求List[left]到List[right]的最大子列和
int MaxLeftSum, MaxRightSum; //存放左右子问题的解
int MaxLeftBorderSum, MaxRightBorderSum; //存放跨分界线的结果
int LeftBorderSum, RightBorderSum;
int center, i;
if( left == right ) //递归的终止条件,子列只有1个数字
if( List[left] > 0 ) return List[left];
else return 0;
//下面是"分"的过程
center = ( left + right ) / 2; //找到中分点
//递归求得两边子列的最大和
MaxLeftSum = DivideAndConquer( List, left, center );
MaxRightSum = DivideAndConquer( List, center+1, right );
//下面求跨分界线的最大子列和
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for( i = center; i >= left; i-- ) { // 从中线向左扫描
LeftBorderSum += List[i];
if( LeftBorderSum > MaxLeftBorderSum )
MaxLeftBorderSum = LeftBorderSum;
} // 左边扫描结束
MaxRightBorderSum = 0; RightBorderSum = 0;
for( i = center + 1; i <= right; i++ ) { // 从中线向右扫描
RightBorderSum += List[i];
if( RightBorderSum > MaxRightBorderSum )
MaxRightBorderSum = RightBorderSum;
} //右边扫描结束
//下面返回"治"的结果
return Max3( MaxLeftSum, MaxRightSum,
MaxLeftBorderSum + MaxRightBorderSum );
}
int MaxSubseqSum3( int List[], int N )
{ //保持与前2种算法相同的函数接口
return DivideAndConquer( List, 0, N-1 );
}
/*在线处理算法,复杂度为O(N),每输入一个数据就进行即时处理,在任何地方中止输入,算法都能正确给出当前的解*/
int MaxSubseqSum4(int A[],int N)
{
int ThisSum,MaxSum;
ThisSum=MaxSum=0;
for(int i=0;i<N;i++){
ThisSum +=A[i];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
else if(ThisSum<0)
ThisSum=0;
}
return MaxSum;
}
int main()
{
int i,N;
scanf("%d",&N);
int a[N];
for(i=0;i<N;i++){
scanf("%d",&a[i]);
}
start=clock();
for(int i=0;i<MAXK;i++) //重复调用函数以获得充分多的时钟打点数
MaxSubseqSum1(a,N);
stop=clock();
duration=((double)(stop-start))/CLK_TCK/MAXK;
printf("%d\n",MaxSubseqSum1(a,N));
printf("ticks1=%f\n",(double)(stop-start));
printf("duration1=%6.2e\n",duration);
start=clock();
for(int i=0;i<MAXK;i++) //重复调用函数以获得充分多的时钟打点数
MaxSubseqSum2(a,N);
stop=clock();
duration=((double)(stop-start))/CLK_TCK/MAXK;
printf("%d\n",MaxSubseqSum2(a,N));
printf("ticks2=%f\n",(double)(stop-start));
printf("duration2=%6.2e\n",duration);
start=clock();
for(int i=0;i<MAXK;i++) //重复调用函数以获得充分多的时钟打点数
MaxSubseqSum3(a,N);
stop=clock();
duration=((double)(stop-start))/CLK_TCK/MAXK;
printf("%d\n",MaxSubseqSum3(a,N));
printf("ticks3=%f\n",(double)(stop-start));
printf("duration3=%6.2e\n",duration);
start=clock();
for(int i=0;i<MAXK;i++) //重复调用函数以获得充分多的时钟打点数
MaxSubseqSum4(a,N);
stop=clock();
duration=((double)(stop-start))/CLK_TCK/MAXK;
printf("%d\n",MaxSubseqSum4(a,N));
printf("ticks4=%f\n",(double)(stop-start));
printf("duration4=%6.2e\n",duration);
return 0;
}
最大子列和(算法复杂度优化)
最新推荐文章于 2021-10-17 15:51:03 发布