順序表應用7:最大子段和之分治遞迴法 SDUT
阿新 • • 發佈:2018-12-13
順序表應用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;
}