一、问题描述
最大子列和问题
给定 n 个整数组成的序列{ N1, N2, …, Nn },“连续子列”被定义为{ Ni, Ni+1, …,
Nj },其中 1≤i≤j≤n。“最大子列和”则被定义为所有连续子列元素的和中最大者。
输出格式:最大子列和 子数列初始位置 子数列结束位置
测试数据:
8
-1 3 -2 4 -6 1 6 -1
测试数据:
8
4 -3 5 -2 -1 2 6 -2
提示:以下是本篇文章正文内容,下面案例可供参考
二、解决步骤
1.C++代码
#include<iostream>
#define MaxSize 100
using namespace std;
void InitMa( int A[], int N){ //数组归零
for( int i=0; i<N; i++){
A[i] = 0;
}
}
void CopyMa( int A[], int B[], int N ){
for( int i=0; i<N && B[i]; i++ ){
A[i] = B[i];
}
}
int MaxSum_F( int A[], int res[], int left, int right ){ //分而治之:递归
//准备工作
int center, //下标(left, right, )
max_left[3], max_right[3], //左、右最大和 [0]:max, [1]、[2]:下标 (下同)
max_left_center[2], max_center_right[2], max_center[3], //跨界的最大和
left_center, center_right; //跨界前的挣扎
if( left == right ){ //递归出口(当且仅当只有一个一个数时)
if( A[left] > 0){
res[0] = A[left];
res[1] = left;
res[2] = left;
//cout<< res[0] <<" "<< res[1] <<" "<< res[2] <<endl;
return res[0];
}else{
return 0;
}
}
//分
center = (left + right)/2;
InitMa(max_left, 3);
MaxSum_F( A, res, left, center );
CopyMa(max_left, res, 3);
InitMa(max_right, 3);
MaxSum_F( A, res, center + 1, right );
CopyMa(max_right, res, 3);
//求跨界最大和
left_center = 0;
center_right = 0;
InitMa(max_left_center, 2);
InitMa(max_center_right, 2);
for( int i=center; i>=left; i-- ){ //max_left_center
left_center += A[i];
if( left_center > max_left_center[0] ){
max_left_center[0] = left_center;
max_left_center[1] = i; //初始下标
}
}//由center向left加
for( int i=center+1; i<=right; i++){ //max_center_right
center_right += A[i];
if( center_right > max_center_right[0] ){
max_center_right[0] = center_right;
max_center_right[1] = i; //终止下标
}
}//由center+1向right加
//if(max_center[0] < max_left_center[0] + max_center_right[0]){}
max_center[0] = max_left_center[0] + max_center_right[0];
max_center[1] = max_left_center[1];
max_center[2] = max_center_right[1];
//治 max(max_left, max_right, max_center)
// A > B ? (A > C ? A : C) : (B > C ? B : C);
if( max_left[0] > max_right[0] ){ // 也可直接写:max_left > max_right
if( max_left[0] > max_center[0] ){
CopyMa(res, max_left, 3);
//cout<<"max_left"<< res[0] <<"+"<< res[1] <<"+"<< res[2] <<endl;
}else if( max_right[0] < max_center[0] ){
CopyMa(res, max_center, 3);
//cout<<"max_center:"<< max_center[0] <<"+"<< max_center[1] <<"+"<< max_center[2] <<endl;
}
}else {
if( max_center[0] < max_right[0] ){
CopyMa(res, max_right, 3);
//cout<<"max_right:"<< res[0] <<"+"<< res[1] <<"+"<< res[2] <<endl;
}else if( max_center[0] > max_left[0] ){
CopyMa(res, max_center, 3);
//cout<<"max_center:"<< max_center[0] <<"+"<< max_center[1] <<"+"<< max_center[2] <<endl;
}
}
return res[0];
}
//在线:指每输入一个数据就进行即时处理,在任何一个地方终止输入,算法都能正确给出当前的解
void MaxSum_Z( int A[], int res[]){ //在线处理(数列的初始化也可以加入到其中)
int flag = 0, MaxSum = 0;
InitMa(res, 3);
for(int i=1; A[i] != '\0'; i++){
if( flag == 0){ //纪录初始位置
res[1] = i;
flag = 1;
}
//cout<< res[0]<<endl;
res[0] += A[i];
if( res[0] > MaxSum ){
MaxSum = res[0];
res[2] = i;
}else if( res[0] < 0 ){ //一旦为负就丢弃(不可能使后续子数列的和变大)
res[0] = 0;
flag = 0;
}
}
res[0] = MaxSum;
cout<< res[0] <<" "<< res[1] <<" "<< res[2] <<endl;
}
/*
最大子列和问题,输出格式:最大子列和 子数列初始位置 子数列结束位置
测试数据:
8
-1 3 -2 4 -6 1 6 -1
测试数据:
8
4 -3 5 -2 -1 2 6 -2
*/
main(){
int n, res[3],
*A=new int(MaxSize);
cout<<"子列长度n:";
cin>>n;
A[0] = n; //用于存放数列长度
cout<<"输入"<<n<<"个数:";
for( int i=1; i<=n; i++){
cin>>A[i];
}
cout<<endl;
cout<<"‘分而治之’的结果:"; //递归思想
InitMa(res, 3);
MaxSum_F(A, res, 1, n);
cout<< res[0] <<" "<< res[1] <<" "<< res[2]<<endl;
cout<<endl<<endl;
cout<<"‘在线处理’的结果:";
MaxSum_Z( A, res );
//cout<< res[0] <<" "<< res[1] <<" "<< res[2] <<" "<< A[0] <<endl;
}
2.运行结果
-
测试数据1
子列长度n:8 输入8个数:-1 3 -2 4 -6 1 6 -1 ‘分而治之’的结果:7 6 7 ‘在线处理’的结果:7 6 7 Process returned 0 (0x0) execution time : 2.626 s Press any key to continue.
-
测试数据:
子列长度n:8 输入8个数:4 -3 5 -2 -1 2 6 -2 ‘分而治之’的结果:11 1 7 ‘在线处理’的结果:11 1 7 Process returned 0 (0x0) execution time : 1.401 s Press any key to continue.