2021-07-16:最大子列和问题——分治法(C++)

本文介绍了如何运用分治算法解决最大子列和问题,提供了C++实现代码,并展示了运行结果。文章通过详细步骤解释了算法的思路和应用。
摘要由CSDN通过智能技术生成


一、问题描述

最大子列和问题

给定 n 个整数组成的序列{ N​1​​, N​2​​, …, N​n​​ },“连续子列”被定义为{ N​i​​, N​i+1​​, …,
N​j​​ },其中 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. 测试数据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.
    
  2. 测试数据:

    子列长度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.
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

门牙磕掉了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值