三种算法
第一种算法(穷举法)
第二种算法(分而治之)
①求左半边最大值
②求右半边最大值
③求横跨中间线的最大值:
1)从中间线处向左扫描找到最大值;
2)向右扫描,与上一步所得相加求最大值
④将三个最大值比较取最大值
代码
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 );
}
算法三(在线处理)
例题
01
#include<stdio.h>
#include<stdlib.h>
int findmax(int a,int b,int c);
int maxsum(int num[],int left,int right);
int main()
{
int n,i,*num;
scanf("%d",&n);
num = (int * )malloc(sizeof(int)*n);
for(i = 0;i<n;i++)
{
scanf("%d",&num[i]);
}
printf("%d",maxsum(num,0,n-1));
return 0;
}
int findmax(int a,int b,int c)
{
a = a>b?a:b;
return a>c?a:c;
}
int maxsum(int num[],int left,int right)
{
int mid,lsum,rsum,msum,i;
if(left == right)
{
return num[left]>0?num[left]:0; 为负时返回0
}
else if(left<right)
{
mid = (left+right)/2;
lsum = 0;rsum = 0;msum = 0;
lsum = maxsum(num,left,mid); 左边一半最大和
rsum = maxsum(num,mid+1,right); 右边一半
msum = 0; 求跨越中间线的最大值
int tsum = msum;
for (i = mid;i>=left;i--)
{
tsum += num[i];
if(tsum>msum){
msum = tsum;
}
}
tsum = msum; !!!第一次写的时候忘记了
for(i = mid+1;i<=right;i++)
{
tsum += num[i];
if(tsum>msum){
msum = tsum;
}
}
return findmax(lsum,rsum,msum);
}
}
02(输出起始终止的数)
#include<stdio.h>
int main()
{
int n,i,sum,tsum,start,tstart,stop;
scanf("%d",&n);
int num[n];
for(i = 0;i<n;i++)
{
scanf("%d",&num[i]);
}
sum = -1; 当sum=0 时也可
tsum = 0;
start = 0;
tstart=0;
stop = n-1;
for(i = 0;i<n;i++)
{
tsum+=num[i];
if(tsum>sum)
{
sum = tsum;
start = tstart;
stop = i;
}
else if(tsum<0) tsum<0 的时候,重新开始一段序列
{
tsum = 0;
tstart = i+1; 是tstart,如果是start,start会一直动
}
}
if(sum>=0)
{
printf("%d %d %d",sum,num[start],num[stop]);
}
else sum<0的时候,输出0
printf("%d %d %d",0,num[0],num[n-1]);
return 0;
}