1. 程式人生 > >[線性DP]最長不下降子序列(LIS)

[線性DP]最長不下降子序列(LIS)

題目:

線上性動態規劃中狀態是一維的,第i個元素的狀態與前i-1個元素的狀態有關,前i-1個狀態組成一個決策序列,它是其他類動態規劃的基礎。典型的應用有LIS(最長不下降子序列),LCS(最長公共子序列)以及它們的應用。

例1 求最長不下降子序列。

由n個不相同的整陣列成的數列,記為:a(1),a(2),…,a(n)且a(i)≠a(j)(i≠j),例如,3,18,7,14,10,12,23,41,16,24.若存在i1<

i2<i3<…<ie且有a(i1)<a(i2)<…<a(ie),則稱其為長度為e的不下降子序列。如上例中3,18,23,24就是一個長度為4的不下降子序列,同時也有3,7,10,12,16,24長度為6的不下降子序列。程式要求,當原數列給出之後,求出最長的不下降子序列的資料個數。

輸入檔案:

第一行為N(1≤N≤5000),第二行為N個整數,之間用空格隔開。

輸出檔案:

最長的不下降子序列的資料個數。

輸入樣例:

10

3 18 7 14 10 12 23 41 16 24

輸出樣例:

6

思路:

DP入門題,狀態轉移方程:f[i] = max{ f[j] } + 1 (1 <= j < i);

狀態轉移方程f[i] = max{ f[j] }+1 要求a[j] < a[i], 那a[j] > a[i]怎麼辦?

我一開始有這樣的疑問,其實是對 f[i] 有誤解:

f[i] 不代表到 i 位置為止的最長不下降子序列的個數

f[i] 代表以 a[i] 為結尾

的最長不下降子序列的個數,基於以 a[i] 為結尾這個條件,自然 a[j] < [i],最後只需要遍歷一遍 f[i] 求其最大值就好

程式碼:

#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>
using namespace std;
/*
狀態轉移方程f[i] = max{f[j]} +1 (1 <= j < i);
f[i] 代表以 a[i] 結尾的最長不下降子序列
最後只需要遍歷一遍f[0~n-1]最大的是誰就好
*/

int f[20];
int maxn;
int n;
void LIS_dp(int *a)
{
    for(int i = 0; i < n; i++)
    {
        f[i] = 1;
        for(int j = 0; j < i; j++)
        {
            if(a[i] > a[j] && f[j]+1 > f[i])
                f[i] = f[j] + 1;
        }
    }
}
int main()
{
    int a[10];
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%d", &a[i]);
    LIS_dp(a);
    int t = 0;
    for(int i = 0; i < n; i++)
        if(f[i] > t)
            t = f[i];
    printf("%d", t);
    return 0;
}
/*
10
3 18 7 14 10 12 23 41 16 24
*/

反思:

關注 f[i] 或者 f[i][j] 等所代表的確切意思