3.給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)-窮舉法,分治法
阿新 • • 發佈:2022-03-19
3.給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數)-分治法
參考文獻:程式設計珠璣第八章-分治演算法
分治演算法求解:
#include <stdio.h> #define max(a,b) a>b?a:b //--------------------------------- // // 需求: // 給定一個整數序列,求其中整數加起來最大子序列和(因為該數列中可能有負數) // //-------------------------------- //--------------------- //法1:直接翻譯的解法(窮舉法) // 時間複雜度:O(n^3) //----------------------- int MaxSubseqSum1(int A[], int N) { int ThisSum, MaxSum = 0; int i, j; for (i = 0; i < N; i++) {//i是子列的左端位置 for (j = i; j < N; j++) {//j是子列的右端位置 ThisSum = 0; for (int z = i; z <= j; z++) { ThisSum += A[z]; if (ThisSum > MaxSum) { MaxSum = ThisSum; } } } } return MaxSum; } //--------------- //法1的優化版:(窮舉法優化) // 畫一個圖即可理解,當i為定值時,只要累加j下標所對應的值,就可以找到從i起所對應的最大序列和,如此迴圈則可以找到所有遍歷的最大序列和 // 時間複雜度:O(n^2) //--------------- int MaxSubseqSum2(int A[], int N) { int ThisSum, MaxSum = 0; int i, j; for (i = 0; i < N; i++) {//i是子列的左端位置 ThisSum = 0; for (j = i; j < N; j++) {//j是子列的右端位置 ThisSum += A[j]; if (ThisSum > MaxSum) { MaxSum = ThisSum; } } } return MaxSum; } //----------------- //法3:分治思想 // 4,-3,5,-2,-1,2,6,-2 // // 設計:不會(參考程式設計珠璣) // //------------------ //用於比較3個數值大小 float max1(float a, float b, float c) { if (a > b && a > c) { return a; } else if (b > a && b > c) { return b; } else { return c; } } float arr[] = { 4,-3,5,-2,-1,2,6,-2 }; float maxsum3(int L, int R) { if (L > R) {//表示陣列中沒有元素 return 0; } if (L == R) {//只有一個元素返回該元素相對於0的最大值 return max(0, arr[L]); } int m = (L + R) / 2;//中位數的下標 /* 以下兩個for迴圈的目的:找出跨越對應的最大子序列和 */ float Lmax = 0, sum = 0; for (int i = m; i >= L; i--) { sum += arr[i]; Lmax = max(Lmax, sum); } float Rmax = 0; sum = 0; for (int i = m+1; i <= R; i++) { sum += arr[i]; Rmax = max(Rmax, sum); } return max1(Lmax + Rmax, maxsum3(L, m), maxsum3(m+1, R)); } int main(void) { float sumMax = maxsum3(0, 7); printf("%f\n", sumMax); }
執行結果: