给定由n(1<n<100)个整数(包含负整数)组成的序列a1,a2,...,an,要在这n个数中选取相邻的一段ai,ai+1,...aj(1≤i≤j≤n),使其和最大,输出该序列子段和的最大值。
给定由n(1<n<100)个整数(包含负整数)组成的序列a1,a2,...,an,要在这n个数中选取相邻的一段ai,ai+1,...aj(1≤i≤j≤n),使其和最大,输出该序列子段和的最大值。
输入有多组测试用例
每组测试用例由2行组成,第一行一个整数n,接下来第二行有n个整数
若整数n为0,表示输入结束
输出该序列子段和的最大值
8
1 -3 7 8 -4 12 -10 6
0
23
/*前置代码*/
#include<iostream>
#include<cstdio> using namespace std; const int maxn = 1005; int a[maxn], _max[maxn]; /*在此加入工作代码 eg: work() */ /*后置代码*/ int main() { //freopen("in.txt","r",stdin); while(cin>>n, n) { for(int i = 1; i <= n; i ++) { cin>>a[i];//在整个过程为方便操作,我们数组的下表从 “1” 开始。 } work(); //or work(1,n); cout<<m<<endl; } return 0; }
我们很容易能够想到暴力的方法,利用三个循环嵌套。(O(n^3))
//1.暴力法
void work()
{
for(int i = 1; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
int curm = 0;//保存当前的和。
for(int k = i; k <= j; k++)
{
curm += a[k];
if(curm > m)
{
m = curm;
}
}
}
}
}
观察发现,暴力法存在大量的重复计算,可以进行一定的优化。(O(n^2))
//2.优化代码
void work()
{
for(int i = 1; i <= n; i++)
{
int curm = 0;
for(int j = i; j <= n; j++)
{
curm += a[j];
if(curm > m)
{
m = curm;
}
}
}
}
优化的效率任不是很高,我们可以考虑分治法。(O(nlog(n)))
将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
n]的最大子段和相同
(3)a[1
n]的最大子段和为ai+
+aj,1<=i<=n/2,n/2+1<=j<=n
我们的目的是求出上述三种情况中最大的一种。
//3.分治法
int work(int l, int r)//l: left r: right { if(l == r) m = a[l];// > 0 ? a[l] : 0; else { int c = (l + r) / 2;//c: center int lm = work(l,c);//lm: left sum int rm = work(c+1,r);//rm: right sum int clm = 0;//center‘s left sum int tlm = 0;//temp left sum for(int i = c; i >= l; i--) { tlm += a[i]; if(tlm > clm) clm = tlm; } int crm = 0;//center‘s right sum int trm = 0;//temp right sum for(int i = c + 1; i <= r; i++) { trm += a[i]; if(trm > crm) crm = trm; } int cm = clm + crm;//center sum m = cm < lm ? ( rm < lm ? lm : rm) : (cm < rm ? rm : cm); } return m; }
尽管上述代码已经比暴力好了很多,但是由于递归调用过程存储空间分配所带来的时间浪费有时也是不可小觑的。
我们介绍一种更高效的算法——动态规划(O(n)),过程如下:
记 _max[i] 为a[0…i]中,包含a[i]的最大子段和,则有
(1) _max[i] = s[i-1]+a[i], s[i-1] > 0,
(2) _max[i] = a[i], s[i-1] <= 0;
我们的目的是求max(_max)
//4.动态规划
void work()
{
m =a[1];
_max[1] = a[1];
for(int i = 2; i <=n; i++)
{
_max[i] = _max[i-1] > 0 ? _max[i - 1] + a[i] : a[i];
if(m < _max[i])
m = _max[i];
}
}
原文:http://www.cnblogs.com/yqbeyond/p/4457517.html