1. 程式人生 > >分治法求解最大子陣列問題

分治法求解最大子陣列問題

/*
最大子陣列問題
給出每天股票的價格,求出買進和賣出的時間,使得獲利最高。
輸入: P[0~n-1]
輸出: 買進的時間i和賣出的時間j(0<=i<=j<=n-1)
*/

//分治法求解,將陣列P轉換為陣列A,其中A中每個元素A[i]=P[i]-p[i-1],表示第i-1天買進,第i天賣出的獲利。
//那麼第i天買進第j天賣出的獲利可以表示為A[i+1]+...+A[j],0<=i<j<n
//經過這樣的轉換後,問題就成了尋找A中最大的非空連續陣列,稱為最大子陣列。

//利用分治法求解
//當陣列A的長度為1時,A[left,right],left=right,那麼i=left-1,j=right;
//當陣列A的長度大於1時,將陣列A一分為二:m=(left+right)/2; //最大子陣列存在的位置有三個位置:1.陣列A[left,m]中;2.陣列A[m+1,right]中;3.橫跨陣列A[left,m]和A[m+1,right],即i在left~m範圍,j在m+1~right範圍。 // #include <stdio.h> #include <stdlib.h> struct ans { int low, high, sum; }; void FindMaxSub(int A[], int low, int high, struct ans *a); void
FindMaxCrosSub(int A[], int low, int mid, int high, struct ans *a); int main() { int *A = NULL; int B[17] = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 }; int n = 0, i = 0; struct ans Ans; scanf("%d", &n); A = (int *)malloc(sizeof(int)*n); for(i = 0
; i<n; i++){ scanf("%d",A+i); } for (i = n - 1; i>0; i--) { A[i] = A[i] - A[i - 1]; } FindMaxSub(A, 1, n - 1, &Ans); printf("\n low = %d, high = %d, sum = %d\n", Ans.low, Ans.high, Ans.sum); system("pause"); return 0; } void FindMaxSub(int A[], int low, int high, struct ans *a) { if (low == high) { a->low = a->high = low; a->sum = A[low]; } else { struct ans a1, a2, a3; int mid = (low + high) / 2; FindMaxSub(A, low, mid, &a1); FindMaxSub(A, mid + 1, high, &a2); FindMaxCrosSub(A, low, mid, high, &a3); // printf("low=%d,mid=%d,high=%d\n", low, mid, high); // printf("a1.low=%d, a1.high=%d, a1.sum=%d\n", a1.low, a1.high, a1.sum); // printf("a2.low=%d, a2.high=%d, a2.sum=%d\n", a2.low, a2.high, a2.sum); // printf("a3.low=%d, a3.high=%d, a3.sum=%d\n", a3.low, a3.high, a3.sum); if (a1.sum >= a2.sum && a1.sum >= a3.sum) { a->low = a1.low; a->high = a1.high; a->sum = a1.sum; } else if (a2.sum >= a1.sum && a2.sum >= a3.sum) { a->low = a2.low; a->high = a2.high; a->sum = a2.sum; } else { a->low = a3.low; a->high = a3.high; a->sum = a3.sum; } //printf("a->low=%d, a->high=%d, a->sum=%d\n", a->low, a->high, a->sum); } } void FindMaxCrosSub(int A[], int low, int mid, int high, struct ans *a) { int leftsum = A[mid], rightsum = A[mid + 1]; int minleft, i, maxright, j; int sum = 0; minleft = i = mid; maxright = j = mid + 1; while (i >= low) { sum += A[i]; if (sum>leftsum) { leftsum = sum; minleft = i; } i--; } sum = 0; while (j <= high) { sum += A[j]; if (sum>rightsum) { rightsum = sum; maxright = j; } j++; } a->low = minleft; a->high = maxright; a->sum = (leftsum + rightsum); }