LIS--最長非降子序列
(講DP基本都會講到的一個問題LIS:longest increasing subsequence)
題目詳情:一個序列有N個數:A[1],A[2],…,A[N],求出最長非降子序列的長度。
舉個實際的例子來說,對於這個序列:5,3,4,8,6,7,求出其最長非降子序列的長度。
根據動態規划的基本思想,分析問題的狀態及其狀態轉移方程,假設d(i) = j,i表示取序列的前i個數,j表示這前i個數字的最長非降序列的長度,首先我們來對前面幾個數作分析:d(1) = 1,這個毋庸置疑的,前一個數的LIS就是1,當i = 2時,看到前兩個數是(5, 3)由於3比5要小,所以d(2) = 1;當i = 3時,序列為(5, 3, 4),4比3要大,比5要小,這個時候這個序列的子序列最大的顯然為2,所以d(3) = 2;當i = 4時,序列為(5, 3, 4, 8),8比前三個數都要大,但是要取出最長的非降子序列應該是(3, 4, 8)而不是(5, 8),分析到這里,就知道,在構造狀態轉移方程的時候,等式右邊應該是一個比較結果的最大值,那又是哪些的比較結果呢?動態規划一般是要利用前面所得到的結果,這樣才不會產生重復計算的問題,減少運算量。因此,參加“比較”的應該就是前面計算的到的結果進行比較,最后我們得到狀態轉移方程為
d(i) = max{ 1, d(j)+1} ,且滿足當i > j時,A[i] >= A[j] (注: 對於任意的i,都有d[i] >= 1)
我們來分析一下這個方程,max顯然是為了找到最長的非降子序列,容易理解,在max里面加入1作為比較的一員,是因為,最壞的情況就是序列是單調遞減的,那么每個數都是一個最長非降子序列,一個數的長度當然為1;那d[j]為什么要加1呢,因為你比較的數A[i] >= A[j],那么A[i]就是最長子序列的一員,所以直接在d[j]上加1,分析完畢。
得到了狀態轉移方程,慣例就是通過代碼來實現它。

/* 動態規划 PRO: 一個序列有N個數:A[1],A[2],…,A[N],求出最長非降子序列的長度。 (講DP基本都會講到的一個問題LIS:longest increasing subsequence) */ #include <stdio.h> #include <stdlib.h> #include <string.h> int DPLIS(int Arr[], int n) { int iterx = 0, itery = 0; int maxVal = 0; int *d = (int *)malloc(sizeof(int) * n); memset(d, 0, sizeof(int) * n); for(iterx = 0; iterx < n; iterx++ ) { d[iterx] = 1; for(itery = 0; itery < iterx; itery++) { if(Arr[iterx] >= Arr[itery]) { d[iterx] = d[iterx] > d[itery] + 1 ? d[iterx] : d[itery] + 1; } } if(maxVal < d[iterx]) { maxVal = d[iterx]; } } free(d); return maxVal; } int main(void) { int Arr[100] = {4, 5,3 ,3 ,3 ,3 ,6 ,5 ,1 ,2}; int n = 10; //int i; // for(i = 100; i > 0; i--) // { // Arr[100 - i] = i ; // } printf("the result is %d\n",DPLIS(Arr, n)); return 0; }