1. 程式人生 > >順序表應用7:最大子段和之分治遞迴法 SDUT

順序表應用7:最大子段和之分治遞迴法 SDUT

順序表應用7:最大子段和之分治遞迴法

Time Limit: 10 ms Memory Limit: 400 KiB

Problem Description

給定n(1<=n<=50000)個整數(可能為負數)組成的序列a[1],a[2],a[3],…,a[n],求該序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。當所給的整數均為負數時定義子段和為0,依此定義,所求的最優值為: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n。 例如,當(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)時,最大子段和為20。

注意:本題目要求用分治遞迴法求解,除了需要輸出最大子段和的值之外,還需要輸出求得該結果所需的遞迴呼叫總次數。

Input

第一行輸入整數n(1<=n<=50000),表示整數序列中的資料元素個數;

第二行依次輸入n個整數,對應順序表中存放的每個資料元素值。

Output

一行輸出兩個整數,之間以空格間隔輸出:

第一個整數為所求的最大子段和;

第二個整數為用分治遞迴法求解最大子段和時,遞迴函式被呼叫的總次數。

Sample Input

6 -2 11 -4 13 -5 -2

Sample Output

20 11

Code

把一個段從中間分開成兩個子段,那麼這個段的最大子段和有三種情況: 1. 等於左邊子段的最大子段和。 2. 等於右邊子段的最大子段和。 3. 等於左子段中某一元素到右子段中某一元素的和。 關鍵在於求第三種情況,從中間元素向兩邊求最大和,再把左右的最大和加起來就可以得到了。

#include <bits/stdc++.h>
using namespace std;
int c;
int maxNum(int a[], int left, int right) {
    c++;
    if(left == right) {
        return a[left] > 0 ? a[left] : 0;
    }
    int mid = (left + right) >> 1;
    int leftMax = maxNum(a, left, mid);
    int rightMax = maxNum(a, mid + 1
, right); int leftSum = 0,temp = 0; for(int i = mid; i >= left; i--) { temp += a[i]; leftSum = max(temp, leftSum); } int rightSum = 0;temp = 0; for(int i = mid+1; i <= right; i++) { temp += a[i]; rightSum = max(temp, rightSum); } return max(leftSum + rightSum, max(leftMax, rightMax)); } int main() { int n; int a[50010]; cin>>n; for(int i = 0; i < n; i++) { scanf("%d",&a[i]); } c = 0; int totalMax = maxNum(a, 0, n-1); cout<<totalMax<<" "<<c<<endl; }