[分治] 洛谷P1115 最大連續子段和(分治典例)
阿新 • • 發佈:2019-01-31
題目
題目描述
給出一段序列,選出其中連續且非空的一段使得這段和最大。
輸入輸出格式
輸入格式:
輸入檔案maxsum1.in的第一行是一個正整數N,表示了序列的長度。
第2行包含N個絕對值不大於10000的整數A[i],描述了這段序列。
輸出格式:
輸入檔案maxsum1.out僅包括1個整數,為最大的子段和是多少。子段的最小長度為1。
輸入輸出樣例
輸入樣例#1: 複製
7
2 -4 3 -1 2 -4 3
輸出樣例#1: 複製
4
說明
【樣例說明】
2 ,-4 ,3 ,-1 ,2 ,-4 ,3中,最大的子段和為4,該子段為3,-1,2.
【資料規模與約定】
對於40%的資料,有N ≤ 2000。
對於100%的資料,有N ≤ 200000。
程式碼
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 10000;
int A[maxn];
int maxsum(int *A, int x, int y) {
if (y - x == 1) return A[x];
int m = x + (y - x) / 2;
int maxs = max(maxsum(A, x, m), maxsum(A, m, y));
int v, L, R;
v = 0; L = A[m - 1];
for (int i = m - 1; i >= x; i--) L = max(L, v += A[i]);
v = 0; R = A[m];
for (int i = m; i < y; i++) R = max(R, v += A[i]);
return max(maxs, L + R);
}
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d" , &A[i]);
printf("%d\n", maxsum(A, 0, n));
return 0;
}
思路
1.分治三步走的學習:
- 劃分問題:把問題的例項劃分成自問題
- 遞迴求解:遞迴解決子問題
- 合併問題:合併自問題的解得到原問題的解
2.本題的分治三步走
- 劃分問題:把序列分成元素個數儘量相等的兩半
- 遞迴求解:求出分別位於左半和又半的最佳序列
- 合併自問題:求出起點位於左半,終點位於右半的最佳序列,並與已得最佳序列進行比較。
3.對於求第三步的最佳序列,可以分解為求終點在分治點的最佳序列和起點在分治點的最佳序列,將它們加起來就可以得到需要的,複雜度降為O(n)。