最大連續和
問題:給出一個長度為n的序列a1,a2,a3....an,求最大連續和,即找到1<=i<=j<=n,是的ai+...+aj最大
1.暴力枚舉
int sum = 0;
int max = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
sum = 0;
for (int k = i; k <= j; k++)
sum += a[k];
if (max < sum)
max = sum;
}
}
T(n)=n(n+1)(n+2)/6=O(n3)
2.遞推
利用前綴
int s[100];
int max = 0;
s[0] = a[0];
for (int i = 1; i < n; i++)
s[i] = s[i - 1] + a[i];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int t = i == 0 ? s[j] : s[j] - s[i - 1];
max = Max(max, t);
}
}
T(n)=O(n2)
3.分治法
1)劃分:把序列分成元素個數盡量相等的兩半;
2) 遞歸求解:分別求出完全位於左半或者完全位於右半的最佳序列
3)合並:求出起點位於左半,終點位於右半的最大連續和序列,並和子問題的最優解比較
關鍵在於“合並”步驟,既然起點位於左半,終點位於右半,我們可以認為地把這樣的序列分成兩部分,
然後獨立求解:先尋找最佳起點,然後再尋找最佳終點。
int maxsum3(int a[], int left, int right) { //左閉右開
int i, m, v, L, R, max;
if (right - left == 1) return a[left];
m = left + (right - left) / 2; //第一步,劃分成[left,m),[m,right)
max = Max(maxsum3(a, left, m), maxsum3(a, m, right));
//第二步,遞歸求解
//第三步,合並
v = 0; L = a[m - 1];
for (i = m - 1; i >= left; i--)
L = Max(L, v += a[i]);
v = 0; R = a[m];
for (i = m; i < right; i++)
R = Max(R, v += a[i]);
return Max(max, L + R);
}
// 練習.cpp: 定義控制臺應用程序的入口點。 // #include "stdafx.h" #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #include<time.h> #include<windows.h> using namespace std; int Max(int a, int b) { return a > b ? a : b; } //暴力枚舉 int maxsum1(int a[], int n) { int sum = 0; int max = 0; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { sum = 0; for (int k = i; k <= j; k++) sum += a[k]; if (max < sum) max = sum; } } return max; } //遞推前綴 int maxsum2(int a[], int n) { int s[100]; int max = 0; s[0] = a[0]; for (int i = 1; i < n; i++) s[i] = s[i - 1] + a[i]; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { int t = i == 0 ? s[j] : s[j] - s[i - 1]; max = Max(max, t); } } return max; } //分治法 int maxsum3(int a[], int left, int right) { //左閉右開 int i, m, v, L, R, max; if (right - left == 1) return a[left]; m = left + (right - left) / 2; //第一步,劃分成[left,m),[m,right) max = Max(maxsum3(a, left, m), maxsum3(a, m, right)); //第二步,遞歸求解 v = 0; L = a[m - 1]; //第三步,合並 for (i = m - 1; i >= left; i--) L = Max(L, v += a[i]); v = 0; R = a[m]; for (i = m; i < right; i++) R = Max(R, v += a[i]); return Max(max, L + R); } int main() { int n; int a[100]; cin >> n; for (int i = 0; i < n; i++) { cin >> a[i]; } int s1 = maxsum1(a, n); int s2 = maxsum2(a, n); int s3 = maxsum3(a, 0, n); cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; system("pause"); return 0; }
最大連續和