1. 程式人生 > >最大子陣列問題【動態規劃】

最大子陣列問題【動態規劃】

       昨天偶然上csdn,看到這個問題,學習了一種複雜度為O(n)的演算法,可以計算Array的最大子陣列問題。思路就是從0-length,將array累加起來,同時用一個變數max記錄最大值,如果sum > max,就更新max,如果sum < 0 就令sum = 0(為什麼是這樣呢,sum < 0的話,前面的就可以直接捨棄了)。附上程式碼:

#include <iostream>
using namespace std;

void MaxSubArray(int array[], int len) {
  int sum = 0, max = array[0], s = 0, s_pos = 0, e_pos = 0;
  for (int i = 0; i < len; i++) {
    sum += array[i];
    //sum > max 更新 max, 並把終點位置置為 i 
    if (sum > max) {
      e_pos = i;
      s_pos = s;
      max = sum;
    }
    //sum < 0的話,就該把前面的拋棄,並且重置sum 為 0, 起始位置為 i + 1 
    if (sum < 0) {
      sum = 0;
      s = i + 1;
    }
    //sum > 0,繼續 (假設最大子陣列在中間 array[i~j]
    //因為 array[k~i-1]的和大於0,則array[k~j]顯然是更大的子陣列) 因此 sum > 0時候,繼續 
  }
  cout << "start position: " << s_pos << endl;
  cout << "end   position: " << e_pos << endl;
  cout << "max value: " << max << endl;
}

int main()
{
int A[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
MaxSubArray(A, sizeof(A)/sizeof(int));
system("pause");
return 0;
}



      接著又看到一篇動態規劃的最大子陣列問題http://blog.csdn.net/xjm199/article/details/17953753,看了下,覺得這跟上面的方法就是一樣的,那個dp[i]也不是記錄著dp[0~i]的最大子陣列問題,於是我就想用dp[i]記錄dp[0~i]的最大子陣列問題值,用動態規劃,就是考慮當前的array[i]是不是最大子陣列的一員,如果是要怎麼做,不是要怎麼做,程式碼如下:

#include <iostream>
#define SIZE 9
using namespace std;

void MaxSubArray(int array[], int dp[], int len) {
  dp[0] = array[0];           //只有一個元素時,dp[0]顯然為array[0] 
  int end_position = 0;       //記錄最大子陣列末尾點 
  for (int i = 1; i < len; i++) {
    int max = array[i], sum = 0, sum2 = 0, j, s0 = i, st = i, en = i;
    /*這個for迴圈是表示子陣列要包括Array[i],則從i到end_position
    看看此陣列的中最大子陣列和為多少*/ 
    for (j = i; j > end_position; j--) {
      sum += array[j];
      sum2 += array[j];
      if (sum > max) {
        max = sum;
        en = j;
        st = s0;
      }
      if (sum < 0) {
        sum = 0;
        s0 = j + 1;
      }
    }
    //sum2>0 && dp[i-1] + sum2 > max,則array[end_position~i]與array[0~i]合併才是當前陣列最大子陣列值 
    if (sum2 > 0 && dp[i-1]+sum2 > max) {
      dp[i] = dp[i-1]+sum2;
      end_position = st;
    } else if (dp[i-1] > max) {     //不能合併時,讓dp[i]等於dp[i-1]和max的大者 
        dp[i] = dp[i-1];
    } else {
        dp[i] = max;
        end_position = st;
    }
  }
  for (int i = 0; i < len; i++)
    cout << dp[i] <<  ' ';
}
int main() {
  int A[] = {18, 20, -7, 12, -5, -22, 15, -4, 7};
  int dp[SIZE];
  MaxSubArray(A, dp, SIZE);
  system("pause");
  return 0;
}


array[]= {18, 20 , -7, 12} ,dp[2] = 38, end_position = 1(最大子陣列的末尾下標, dp[2]表示array[0-2]的子陣列最大值),則dp[3]的求法為,先看看-7+12 是否是大於0的,如果大於0,則18 20 -7 12合併後顯然比dp[2]更大,應該合併,這時也得找出-7 12 這個陣列最大子陣列值,顯然是12,拿12和合並後的比較取較大者,然後更新end_position。繼續迴圈