一.分治算法思路
给定n个整数组成的序列 a1,a2,…,an,求该序列的字段和的最大值。当所有整数均为负数的时定义其最大子段和为0。
如序列: 2,4,-3,5,-1,-7,6
该序列的最大子段为:2,4,-3,5
最大字段和为:8
对于这个问题,我们可以使用分治思想,将a[1:n]分成对等的两段a[1:n/2]和a[n/2+1:n],这样这个问题便被分解了三部分:
1. a[1:n]最大子段和与a[1:n/2]最大子段和相同
2. a[1:n]最大子段和与a[n/2+1:n]最大子段和相同
3. a[1:n]最大子段和位于数组的中间部分
前两种情况可以使用递归调用获得,而第三种情况则需要以分界点为界,分别向两边计算,最后将两边计算的结果进行相加。最后将三种结果进行比较,最终输出最大子段和。
例如:-2,11,-4,13,-5,-2
以n/2为分界点:
-2,11,-4
13,-5,-2
左边最大子段和为:11
右边最大子段和为:13
中间段最大子段和为:20
最后输出 20
二.代码实现
#include<iostream>
using namespace std;
int MaxSum(int a[],int left,int right,int *left_Partion,int *right_Partion)
{
int center,sum_left,sum_right,sum;
if (left==right)
{
if (a[left]<0)
{
return 0;
*left_Partion = left;
*right_Partion = left;
}
else
return a[left];
}
else
{
center=(left+right)/2;
sum_left=MaxSum(a,left,center,left_Partion,right_Partion);
sum_right=MaxSum(a,center+1,right,left_Partion,right_Partion);
//求中间子段
int s1=0,lefts=0;
for (int i = center; i >= left; i--)
{
lefts=lefts+a[i];
if (s1<lefts)
{
s1=lefts;
*left_Partion=i;
}
}
int s2=0,rights=0;
for (int i = center+1; i < right; i++)
{
rights=rights+a[i];
if (s2 < rights)
{
s2=rights;
*right_Partion=i;
}
}
sum=s1+s2;
//比较大小
if ((sum_left>sum_right)&&(sum_left>sum))
{
return sum_left;
}
else if (sum_left>sum)
{
return sum_right;
}
return sum;
}
}
int main(int argc, char const *argv[])
{
cout <<"请输入数组个数:";
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
int sum=0;
int x,y;
sum=MaxSum(a,0,n,&x,&y);
cout << sum <<endl;
for (int i = x; i <= y; i++)
{
cout << a[i] <<"\t";
}
cout << endl;
system("pause");
return 0;
}
三.动态规划算法思路及代码实现
重新定义一个数组b[n],令b[i]=b[i-1]+a[1],若b[i]<0则b[i]=0。最大子段和的值即为b[n]数组的最大值。
将这串数字的和存入数组b
-2 11 -4 13 -5 -2
b[1]=a[1]=-2<0
b[2]=b[1]+a[2]=11
b[3]=b[2]+a[3]=7
b[4]=b[3]+a[4]=20
b[5]=b[4]+a[5]=15
b[6]=b[5]+a[6]=13
#include<iostream>
using namespace std;
int MaxSum(int a[],int c[],int n,int *p)
{
c[0]=0;
for (int i = 1; i <= n; i++)
{
c[i]=c[i-1]+a[i];
if (c[i]<0)
{
c[i]=0;
}
cout<<"i="<<i<<" "<<c[i]<<endl;//输出每个c[i]的值
}
int max=c[1];
for (int i = 2; i <= n; i++)
{
if (max<c[i])
{
max=c[i];
*p=i;
}
}
return max;
}
int main(int argc, char const *argv[])
{
cout <<"请输入数组个数:";
int n,p;
cin >> n;
int *a=new int [n];
int *c=new int [n];
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
int result=MaxSum(a,c,n,&p);
cout << result <<endl;
int s=0,i;
for(i=p;i>=0;i--)
{
s+=a[i];
if(s==result && i>=0)
break;
}//从c[i]最大的位置向前寻找,找到子段和的第一个位置
if(i<0) i=0;
cout<<i<<"-"<<p<<endl;
system("pause");
return 0;
}