分而治之的思想(divide and conquer)
#include<iostream>
using namespace std;
int max(int a,int b)
{
return (a>b)?a:b;
}
int MaxSum(int *A,int low,int high)
{
//leftMax记录数组左半边最大的值
//rightMax记录数组右半边最大的值
int leftMax,rightMax;
if((high-low)==0)
return A[low];
int mid=low+(high-low)/2;
leftMax=MaxSum(A,low,mid);
rightMax=MaxSum(A,mid+1,high);
int lparsum,lmaxparsum,rparsum,rmaxparsum;
//注意这里初始化为中间的值,若初始化为0
//则全是负数的数组返回的结果为0
//而需要返回的结果为这个负数数组中最大的数
//lmaxparsum记录左半边以A[mid]结尾的最大的子数组和
//rmaxparsum记录右半边以A[mid+1]开始的最大的子数组和
lparsum=lmaxparsum=A[mid];
rparsum=rmaxparsum=A[mid+1];
for(int i=mid-1;i>=low;i--)
{
lparsum+=A[i];
if(lmaxparsum<lparsum)
lmaxparsum=lparsum;
}
for(int j=mid+2;j<=high;j++)
{
rparsum+=A[j];
if(rmaxparsum<rparsum)
rmaxparsum=rparsum;
}
int spanmax=lmaxparsum+rmaxparsum;
return max(max(leftMax,rightMax),spanmax);
}
int main()
{
int A[6]={1,-2,3,5,-3,2};
int B[6]={0,-2,3,5,-1,2};
int C[5]={-9,-2,-3,-5,-3};
cout<<MaxSum(A,0,5)<<" ";
cout<<MaxSum(B,0,5)<<" ";
cout<<MaxSum(C,0,4)<<" "<<endl;
int i;
cin>>i;
return 0;
}
#include<iostream>
using namespace std;
int max(int a,int b)
{
return (a>b)?a:b;
}
int MaxSum(int *A,int size)
{
int nStart=A[size-1];
int nAll=A[size-1];
int sum=A[size-1];
for(int i=size-2;i>=0;i--)
{
nStart+=A[i];
nStart=max(A[i],nStart);
nAll=max(nStart,nAll);
}
return nAll;
}
int main()
{
int A[6]={1,-2,3,5,-3,2};
int B[6]={0,-2,3,5,-1,2};
int C[5]={-9,-2,-3,-5,-3};
cout<<MaxSum(A,6)<<" ";
cout<<MaxSum(B,6)<<" ";
cout<<MaxSum(C,5)<<" "<<endl;
int i;
cin>>i;
return 0;
}
动态规划版:
扩展问题1
当数组首尾相连时,求子数组之和的最大值
这时需解可能跨越A[0]与A[n-1]的情况,可以分两段计算
以A[0]开始的数组的最大值(A[0],A[1],...A[i])
以A[n]结尾的子数组的最大值(A[j],A[j+1],...A[n-1])
若i<j
则含有A[0]与A[n-1]的最大值为
A[0]+A[1]+...+A[i]+(A[j]+...A[n-1]
若i>j
如数组中无负数
则含有A[0]与A[n-1]的最大值为
整个数组的和
否则需用整个数组的和减去子数组之和的最小值(子数组之和为负)
A[0]+A[1]+..A[n-1]-min(子数组之和)
#include<iostream>
using namespace std;
int max(int x,int y){
return (x>y)?x:y;
}
int min(int x,int y){
return (x<=y)?x:y;
}
int MaxSum(int *A,int n){
//nSpan为数组头尾相连时
//跨越A[0]与A[n-1]的最大的值
//还要求出子数组之和为负时的最小值
int nSpan=0;
int nStart,nAll;
//negAll记录子数组之和的最小值
//negStart记录从数组某个索引开始的最小值
int negStart,negAll;
negStart=0;
negAll=0;
int temp_sum;
int Start,All;
nStart=A[n-1];
nAll=A[n-1];
int i;
int j,k;
int j_index;
//以A[0]开始的最大的和
int start_Sum=0;
int start_Index;
//以A[n-1]结束的最大的和
int end_Sum=0;
int end_Index;
for(i=n-2;i>=0;i--){
nStart+=A[i];
nStart=max(A[i],nStart);
if(nStart>nAll)
nAll=nStart;
}
start_Sum=A[0];
start_Index=0;
temp_sum=start_Sum;
for(j=1;j<n;j++){
temp_sum+=A[j];
if(start_Sum<temp_sum){
start_Sum=temp_sum;
start_Index=j;
}
}
end_Sum=A[n-1];
end_Index=n-1;
temp_sum=end_Sum;
for(k=n-2;k>=0;k--){
temp_sum+=A[k];
if(end_Sum<temp_sum){
end_Sum=temp_sum;
end_Index=k;
}
}
if(start_Index<end_Index){
nSpan=start_Sum+end_Sum;
return max(nAll,nSpan);
}
else{
for(i=n-1;i>=0;i--){
//求出子数组之和最小的值
negStart=min(A[i],A[i]+negStart);
negAll=min(negStart,negAll);
}
if(negAll<0){
for(i=0;i<n;i++)
nSpan+=A[i];
nSpan-=negAll;
return nSpan;
}
return nAll;
}
}
int main(){
int A[]={4,5,6,-7,8,9,10};
cout<<MaxSum(A,7)<<endl;
system("pause");
return 0;
}
扩展问题2
只要设置索引变量保存索引即可
#include<iostream>
using namespace std;
int MaxSum(int *A,int size,int& all_Low,int& all_High)
{
int start_Low;
int start_High;
int nStart=A[size-1];
int nAll=A[size-1];
int sum=A[size-1];
start_High=size-1;
all_Low=size-1,all_High=size-1;
for(int i=size-2;i>=0;i--)
{
start_Low=i;
nStart+=A[i];
if(A[i]>nStart){
start_High=i;
nStart=A[i];
}
if(nStart>nAll){
all_Low=start_Low;
all_High=start_High;
nAll=nStart;
}
}
return nAll;
}
int main()
{
int low;
int high;
int A[6]={1,-2,3,5,-3,2};
int B[6]={0,-2,3,5,-1,2};
int C[5]={-9,-2,-3,-5,-3};
cout<<MaxSum(A,6,low,high)<<" ";
cout<<"low="<<low<<" "<<"high="<<high<<endl;
cout<<MaxSum(B,6,low,high)<<" ";
cout<<"low="<<low<<" "<<"high="<<high<<endl;
cout<<MaxSum(C,5,low,high)<<" "<<endl;
cout<<"low="<<low<<" "<<"high="<<high<<endl;
system("pause");
return 0;
}