動態規划---LIS


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;
}
View Code

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM