【算法设计与分析】暴力、分治、动态规划——最大子段和问题
问题描述
给定由n个整数(可能有负整数)组成的序列(a1,a2,…an),求该序列子段和的最大值,当所有整数均为负整数时,其最大子段和为0
暴力
1.从第一个数开始计算长度为1、2……n的字段和,将这一段的最大字段和保存起来
2.再从第2个数开始计算长度为1、2……n-1的字段和,将这一阶段的最大字段和与前一阶段求得的最大字段和比较,取最大的保存下来
3.以此类推,最后保存的即为整个程序的最大字段和。
代码如下
int MaxSubStringSum_BF(vector<int> v)
{
int n = v.size(),maxSum=0,sum=0;
for(int i=0;i<n;i++)
{
sum =0;
for(int j=i;j<n;j++)
{
sum = sum + v[j];
if(sum>maxSum) maxSum=sum;
}
}
return maxSum;
}
分治
1.将子段分成长度相等的两段
2.求出左边子段的最大字段和
3.求出右边子段的最大字段和
4.求出横跨左右两段的最大字段和
5.求出三者中的最大值即解
代码如下
int MaxSubStringSum_FenZhi(vector<int> v,int m,int n)
{
int sum =0;
if(n-m==1)
{
if(v[m]>0) sum = v[m];
else sum =0;
}
else
{
int mid = (m+n)/2;
int lsum = MaxSubStringSum_FenZhi(v,m,mid);
int rsum = MaxSubStringSum_FenZhi(v,mid,n);
int ll=0,lmax=0;
for(int i=mid-1;i>=m;i--)
{
ll += v[i];
if(lmax<ll) lmax = ll;
}
int rr=0,rmax=0;
for(int i=mid;i<n;i++)
{
rr += v[i];
if(rmax<rr) rmax = rr;
}
sum = lmax+rmax;
if(sum<lsum) sum = lsum;
if(sum<rsum) sum = rsum;
}
return sum;
}
动态规划
1.temp表示以v[i-1]结尾的子串的最大子段和,如果temp>=0,那么以v[i]结尾的子串的最大子段和一定是temp+v[i];
2.如果temp<0,那么以v[i]结尾的子串的最大子段和为v[i];
3.从头遍历一次记录最大的temp即为最大子段和;
代码如下
int MaxSubStringSum_dp(vector<int> v)
{
int n = v.size();
int maxSum =0,temp=0;
for(int i=0;i<n;i++)
{
if(temp>=0) temp+=v[i];
else temp= v[i];
if(maxSum<temp) maxSum=temp;
}
return maxSum;
}
int main()
{
int k;
vector<int> v;
while(cin >> k && k!=-1)
v.push_back(k);
cout << "暴力法得到的结果:" << MaxSubStringSum_BF(v)<<endl;
cout << "分治法得到的结果:" << MaxSubStringSum_FenZhi(v,0,v.size()) << endl;
cout << "动态规划法得到的结果:" << MaxSubStringSum_dp(v) << endl;
return 0;
}
/*
1 -3 2 3 -4 23 33 -2 6 -1
*/
结果如下