1 #include <iostream> 2 #include <ctime> 3 using namespace std; 4 5 /* 最大子序列和問題求解 6 * 給定數A1, A2, ..., An,求第i個到第j個累積和的最大值。 7 * 若是全部整數均爲負數,則最大子序列和爲0 8 */ 9 10 /* 11 * 方法1:窮舉式地嘗試全部的可能 12 */ 13 int maxSubsequenceSum_1(const int A[], int N) { 14 int thisSum, maxSum, i, j, k; 15 maxSum = 0; 16 for(i = 0; i < N; i++) 17 for(j = i; j < N; j++) { 18 thisSum = 0; 19 for(k = i; k <= j; k++) // 出現大量沒必要要的計算,被過度地耗時 20 thisSum += A[k]; 21 if(thisSum > maxSum) 22 maxSum = thisSum; 23 } 24 return maxSum; 25 } //時間複雜度爲O(N3) 26 27 int maxSubsequenceSum_2(const int A[], int N) { 28 int thisSum, maxSum, i, j; 29 maxSum = 0; 30 for(i = 0; i < N; i++) { 31 thisSum = 0; 32 for(j = i; j < N; j++) { 33 thisSum += A[j]; 34 if(thisSum > maxSum) 35 maxSum = thisSum; 36 } 37 } 38 return maxSum; 39 } //時間複雜度O(N2) 40 41 int max3(int a, int b, int c) { 42 int max; 43 max = a; 44 if(b > max) 45 max = b; 46 if(c > max) 47 max = c; 48 return max; 49 } 50 51 /* 分治(divide-and-conquer)策略 - 52 * 「分」指把問題分紅兩個大體相等的子問題,而後遞歸地對它們求解 53 * 「治」指將兩個子問題的解合併到一塊兒並可能再作些少許的附加工做,最後獲得整個問題的解 54 */ 55 int maxSubSum(const int A[], int left, int right) { 56 int maxLeftSum, maxRightSum; 57 int maxLeftBorderSum, maxRightBorderSum; 58 int leftBorderSum, rightBorderSum; 59 int center, i; 60 61 if(left == right) { // 只有一個元素時 62 if(A[left] > 0) 63 return A[left]; 64 else 65 return 0; 66 } 67 68 // 最大子序列和出如今數據的左半部或者右半部,遞歸求解 69 center = (left + right) / 2; 70 maxLeftSum = maxSubSum(A, left, center); 71 maxRightSum = maxSubSum(A, center+1, right); 72 73 // 最大子序列和佔據左右兩半部分 74 // 求出前半部分的最大和(包含前半部分的最後一個元素) 75 maxLeftBorderSum = 0; leftBorderSum = 0; 76 for(i = center; i >= left; i--) { 77 leftBorderSum += A[i]; 78 if(leftBorderSum > maxLeftBorderSum) 79 maxLeftBorderSum = leftBorderSum; 80 } 81 // 求出後半部分的最大和(包含後半部分的第一個元素) 82 maxRightBorderSum = 0; rightBorderSum = 0; 83 for(i=center+1; i <= right; i++) { 84 rightBorderSum += A[i]; 85 if(rightBorderSum > maxRightBorderSum) 86 maxRightBorderSum = rightBorderSum; 87 } 88 89 return max3(maxLeftSum, maxRightSum, maxLeftBorderSum+maxRightBorderSum); 90 } 91 92 int maxSubsequenceSum_3(const int A[], int N) { 93 return maxSubSum(A, 0, N-1); 94 } // 時間複雜度O(NlogN) 95 96 /* 優勢:只對數據進行一次掃描,一旦A[i]被讀入並被處理,它就再也不須要被記憶 97 * 此外,在任意時刻,算法都能對它已經讀入的數據給出序列問題的正確答案 - 聯機算法 98 */ 99 int maxSubsequenceSum_4(int A[], int N) { 100 int thisSum, maxSum, j; 101 thisSum = maxSum = 0; 102 for(j = 0; j < N; j++) { 103 thisSum += A[j]; 104 if(thisSum > maxSum) 105 maxSum = thisSum; 106 else if(thisSum < 0) 107 thisSum = 0; 108 } 109 return maxSum; 110 } // 時間複雜度O(N) 111 112 int main() { 113 time_t start, end; 114 int A[] = {4, -3, 5, -2, -1, 2, 6, -2, 10, 9, -5, -2, 10, 2, -5, 3}; 115 int maxSum; 116 117 start = clock(); 118 maxSum = maxSubsequenceSum_1(A, 16); 119 cout << maxSum << endl; 120 end = clock(); 121 cout << 1000.0 * (end - start) / CLOCKS_PER_SEC << endl; //執行maxSubsequenceSum_1所花費的時間 122 123 start = clock(); 124 maxSum = maxSubsequenceSum_2(A, 16); 125 cout << maxSum << endl; 126 end = clock(); 127 cout << 1000.0 * (end - start) / CLOCKS_PER_SEC << endl; 128 129 start = clock(); 130 maxSum = maxSubsequenceSum_3(A, 16); 131 cout << maxSum << endl; 132 end = clock(); 133 cout << 1000.0 * (end - start) / CLOCKS_PER_SEC << endl; 134 135 start = clock(); 136 maxSum = maxSubsequenceSum_4(A, 16); 137 cout << maxSum << endl; 138 end = clock(); 139 cout << 1000.0 * (end - start) / CLOCKS_PER_SEC << endl; 140 141 return 0; 142 }
參考書籍《數據結構與算法分析:C語言描述》ios