1. 程式人生 > 實用技巧 >最大子段和問題—分治法

最大子段和問題—分治法

一、問題描述

簡述

給定有n個整數(可能為負整數)組成的序列a1,a2,...,an,求該序列連續的子段和的最大值。 如果該子段的所有元素和是負整數時定義其最大子段和為0。

Input

第一行有一個正整數n(n<1000),後面跟n個整數,絕對值都小於10000。直到檔案結束。

Output

輸出它的最大子段和。

輸入

6 -2 11 -4 13 -5 -2

輸出

20

二、解題思路

分支法基本思想

將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。

解題思路

  1. 對於陣列的最大子段和問題,它最大子段要麼在左半邊,要麼在右半邊,要麼是穿過中間,三種情況
  2. 每次把N個欄位在中間分成兩段用遞迴直至欄位分解成長度為一時在返回陣列下標對應的數
  3. 每次遞迴得到左半邊和右半邊的最大欄位後再求穿過中間的情況對應的最大子段,三者取最大值

三、程式碼

#include <iostream>
#include <math.h>
using namespace std;

int *p;
int f(int l,int r){
    if(l==r)
        return p[r];
    int mid = (l + r)/2;
    int t1 = f(l,mid);
    int t2 = f(mid+1,r);

    int maxl=0,maxr=0;
    int sum = 0;
    for(int i=mid;i>=l;i--){
        sum+=p[i];
        if(sum>maxl)
            maxl = sum;
    }
    sum = 0;
    for(int i=mid+1;i<=r;i++){
        sum+=p[i];
        if(sum>maxr)
            maxr = sum;
    }
    return max(max(t1,t2),maxl+maxr);
}

int main()
{
    int n;
    cin>>n;
    p = new int[n];
    for(int i=0;i<n;i++){
        cin>>p[i];
    }
    int res = f(0,n-1);
    cout<<res<<endl;

    return 0;
}