最大子段和问题

题目要求:
随机给出一个整数序列,用分治法选出其中连续且非空的一段使得这段和最大

主要思路:
先随机生成一组有正负的数组(题目中有为空这个要求,暂时没有找到生成有正负又有空的数组应该怎样生成,后面有时间在看看)
分治法需要将数组从中间分开,那么最大子数组就会有3种情况,要么完全在左半边数组,要么完全在右半边数组,要么跨立在分界点上。最大子数组完全在左数组、右数组采用递归方法解决。int sum1=calc(s,mid,l1,r1);int sum2=calc(mid+1,e,l2,r2);最大连续子数组跨立在分界点上:实际上是左数组的最大后缀和右数组的最大前缀的和。因此,从分界点向前扫,向后扫然后把找到的左边最大后缀和右边最大前缀加起来,得到的值与前两种情况找到的值对比,即可找出该数组的最大连续子数组。
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <ctime>
#include <cmath>
#define N 1000005
using namespace std;
int a[1005];

int calc(int s,int e,int &l,int &r)
{
    int l1,l2,l3,r1,r2,r3;
    ///if(s==e)  return a[s]>0?a[s]:0;
    if(s==e)
    {
        if(a[s]>0)
        {
            l=s;
            r=s;
            return a[s];
        }
        else return 0;
    }
    int mid=(s+e)>>1;
	//cout<<"中间数为"<<mid;
    int sum1=calc(s,mid,l1,r1);  //递归找出在左边的最大连续子数组
    int sum2=calc(mid+1,e,l2,r2); //递归找出右边的最大连续子数组
    int sl=0,sr=0,t=0;
    for(int i=mid; i>=s; i--) //从分界点向前扫,找出左边的最大后缀
    {
        t+=a[i];
        if(sl<t) sl=t,l3=i;
    }
    t=0;
    for(int j=mid+1; j<=e; j++) //从分界点向后扫,找出右边的最大后缀
    {
        t+=a[j];
        if(sr<t) sr=t,r=j,r3=j;
    }
    int ss=sl+sr;  //找出跨在分界线上的最大连续子数组
    l=l3,r=r3;
    if(ss<=sum1) ss=sum1,l=l1,r=r1; //比较三种情况下最大的连续子数组
    if(ss<=sum2) ss=sum2,l=l2,r=r2;
    return ss;
}

int main()
{
    int n;
    printf("输入数列长度:");
    cin>>n;
	cout<<"随机生成的数组为:";
	srand(unsigned(time(NULL)));  //设置随机种子
    for(int i=0;i<n;i++)
    {
        a[i]=(rand()%200)/10-10;    //调整rand(),使得横纵坐标范围为[-10,10]
        cout<<a[i]<<" ";
    }


        int l=1,r=1;
        int sum=calc(1,n,l,r);
        if(sum>0)
        {
            cout<<"最大子段和:"<<sum<<endl;
            cout<<"起点是:第"<<l+1<<"个数"<<a[l]<<","<<"终点是:第"<<r+1<<"个数"<<a[r]<<endl;
        }
        else
        {
            cout<<"最大子段和:"<<sum<<endl;
            cout<<"无起点和终点!"<<endl;
        }
        cout<<endl;
    
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值