演算法設計——最大子段和問題分析
阿新 • • 發佈:2018-12-10
最大子段和問題——分治法應用
問題描述: 給定由n個整數(存在負整數)組成的序列 ,求序列形式如的子段和的最大值。當整個序列所有整數均為負整數時,其最大子段和為0。依次定義,所求的最大值為
例如:當時,最大子段和為最大子段和問題的分治策略如下:
分解。如果將給定的序列A[1…n]分為長度相等的兩段A[1…n/2]和A[n/2+1…n],分別求出這兩段的最大子段和,則經過分析A[1…n]最大欄位和有三種情形。
- A[1…n]的最大欄位和與A[1…n/2]的最大子段和相同。
- A[1…n]的最大欄位和與A[n/2+1…n]的最大子段和相同。
- A[1…n]的最大欄位和與,且滿足。
求解。第一種情況與第二種情況可以利用遞迴進行求解。對於第三種情況,經過分析得出,A[n/2]與A[n/2+1]在最優子序列中。因此可以在A[1…n/2]中計算出,並在A[n/2+1…n]中計算出,則最終計算出為第三種情況下的最優解。
- 合併。比較再分解階段的3種情況下的最大子段和,獲得三者之中的最大值即為問題的求解。
根據以上分析我們可以設計出求解最大子段和的分治演算法如下:
/*--------------最大子段和問題 分治法應用----------------------------------- GetMaxSubSum()說明: Array為陣列、left和right為陣列下標 對於陣列Array長度為n的序列,可以呼叫GetMaxSubSum(Array,0,n-1)來獲得陣列Array中的最大欄位和 ----------------------------------------------------------------------------*/
int GetMaxSubSum(int *Array, int left, int right)
{
int sum = 0;
int i;
//遞迴停止條件
if (left == right)
{
if (Array[left] > 0)
sum = Array[left];
else
sum = 0;
}
else
{
int center = (left + right) / 2;
//遞迴呼叫
int leftSum = GetMaxSubSum(Array, left, center);
int rightSum = GetMaxSubSum(Array, center + 1, right);
int sum1 = 0;
int lefts = 0;
for (i = center; i >= left; i--)
{
lefts = lefts + Array[i];
if (lefts > sum1)
sum1 = lefts;
}
int sum2 = 0;
int rights = 0;
for (i = center + 1; i <= right; i++)
{
rights = rights + Array[i];
if (rights > sum2)
sum2 = rights;
}
sum = sum1 + sum2;
//情況1
if (sum < leftSum)
sum = leftSum;
//情況2
if (sum < rightSum)
sum = rightSum;
return sum;
}
}