最大连续和的不断优化过程
原创、转载请注明出处
给出一个长度为n的序列,求最大连续和
1、n3
#include<iostream> using namespace std; int f(int P[], int n) { int ans = P[0]; for(int i = 0; i < n; i ++) { for(int j = i; j < n; j ++) { int sum = 0; for(int k = i; k <= j; k ++) { sum += P[k]; if(sum > ans)ans = sum; } } } return ans; } int main() { int n; cin >> n; int P[1000],S[1000]; for(int i = 0; i < n; i ++) { cin >> P[i]; } cout << f(P, 0, n) << endl; return 0; }
2、n2
记录、递推思想
int f(int P[], int S[], int n)
{
S[0] = 0;
int ans = P[1];
for(int i = 1; i <= n; i ++)
{
S[i] = S[i-1] + P[i];//S[i]代表从P[1]到P[i]的和
}
for(int i = 1; i <= n; i ++)
{
for(int j = i; j <= n; j ++)
{
if((S[j] - S[i - 1]) > ans)
{
ans = maxS[j] - S[i - 1];
}
}
}
return ans;
}
int main()
{
int n;
cin >> n;
int P[1000],S[1000];
for(int i = 1; i <= n; i ++)
{
cin >> P[i];
}
cout << f(P, S, n) << endl;
return 0;
}
3、nlogn
分治算法一般分为以下3个步骤:
划分问题:把问题的实例划分成子问题。
递归求解:递归解决子问题。
合并问题:合并子问题的解得到原问题的解。
最大连续和的分治算法:
1、把序列分成元素个数尽量相等的两半;2、分别求出完全位于左半或者完全位于右半的最佳序列;3、求出起点位于左半、终点位于右半的最大连续和序列,并和子问题的最优解比较。
#include<iostream> using namespace std; int f(int A[], int x, int y)//返回在[x,y)中的最大连续和 { if(x == y - 1) { return A[x]; } int mid = x + (y - x) / 2, ans = A[x]; ans = max(ans, f(A, x, mid)); ans = max(ans, f(A, mid, y)); int L = A[mid - 1],R = A[mid]; for(int i = x; i < mid; i ++) { int sum = 0; for(int j = i; j < mid; j ++) { sum += A[j]; } L = max(L, sum); } for(int i = mid; i < y; i ++) { int sum = 0; for(int j = i; j < y; j ++) { sum += A[j]; } R = max(R, sum); } ans = max(ans, L + R); return ans; } int main() { int n; cin >> n; int P[1000],S[1000]; for(int i = 0; i < n; i ++) { cin >> P[i]; } cout << f(P, 0, n) << endl; return 0; }
该方法的2个细节:
1、左闭右开的“数组分割”。使得处理自然。
2、(x+y)/2和x+(y-x)/2。数学上等价,在计算机中,前者是朝零取整,后者是朝区间起点取整。
4、n
在O(n2)算法上稍作修改:当j确定时,“S[j]-S[i-1]最大”相当于“S[i-1]最小”,因此只需要扫描一次数组,维护“目前遇到过的最小S”即可。
#include<iostream> using namespace std; int f(int P[], int S[], int n) { S[0] = 0; int ans = P[0]; for(int i = 1; i <= n; i ++) { S[i] = S[i-1] + P[i];//代表从P[0]到P[i]所有元素的和 } int minn = S[1]; for(int i = 1; i <= n; i ++) { minn = min(minn, S[i - 1]); ans = max(ans, S[i] - minn); } return ans; } int main() { int n; cin >> n; int P[1000],S[1000]; for(int i = 1; i <= n; i ++) { cin >> P[i]; } cout << f(P, S, n) << endl; return 0; }