1. 程式人生 > >[分治] 洛谷P1115 最大連續子段和(分治典例)

[分治] 洛谷P1115 最大連續子段和(分治典例)

題目

題目描述

給出一段序列,選出其中連續且非空的一段使得這段和最大。
輸入輸出格式
輸入格式:

輸入檔案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)。