【算法设计与分析】 最大子段和(分治递归)
【问题描述】
使用分治递归算法解最大子段和问题,具体来说就是,将序列分为长度相等的左右两段,分别求出这两段的最大子段和,包含左右部分子段的最大子段和,求这三种情况得到的最大子段和的最大值。
【输入形式】
在屏幕上输入一个序列元素,包含负整数、0和正整数。
【输出形式】
序列的最大子段和,及得到最大子段和时的起始和终止编号。
【样例输入】
-2 11 -4 13 -5 -2
【样例输出】
20
2
4
【样例说明】
输入:6个数,元素间以空格分隔。
输出:序列的最大子段和20,得到最大子段和时的起始编号为2,终止编号为4。
【题解代码】
C++代码:
#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
int a[100],t,n=0,ans=0,ansleft=0,ansright=0;
int Maxsum(int left,int right,int &ansl,int &ansr)
{
int l1=1,r1=1,l2=1,r2=1,l3=1,r3=1;
if(left==right)
{
if(a[left]>0)
{
ansl=ansr=left;
return a[left];
}
else
return 0;
}
else
{
int mid=left+(right-left)/2;
int sum1=Maxsum(left,mid,l1,r1);//情况1:最大子段与左半部分相同
int sum2=Maxsum(mid+1,right,l2,r2);//情况2:最大子段与右半部分相同
int sum3=0,s1=0,s2=0,temp1=0,temp2=0;//情况3:最大子段跨越左右两个部分
for(int i=mid;i>=left;i--)
{
temp1+=a[i];
if(temp1>s1)
{
s1=temp1;
l3=i;
}
}
for(int i=mid+1;i<=right;i++)
{
temp2+=a[i];
if(temp2>s2)
{
s2=temp2;
r3=i;
}
}
sum3=s1+s2;
ansl=l3;
ansr=r3;
if(sum3<=sum1)
{
sum3=sum1;
ansl=l1;
ansr=r1;
}
if(sum3<=sum2)//细节:这里要用<=
{
sum3=sum2;
ansl=l2;
ansr=r2;
}
return sum3;//最大子段优先选择:左>中>右
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
stringstream scin;
string s;
getline(cin,s);
scin<<s;
while(scin>>t)
a[++n]=t;
ans=Maxsum(1,n,ansleft,ansright);
cout<<ans<<endl<<ansleft<<endl<<ansright<<endl;
return 0;
}