動態規划 - 最長遞增子序列(LIS)


最長遞增子序列是動態規划中經典的問題,詳細如下:

在一個已知的序列{a1,a2,...,an}中,取出若干數組組成新的序列{ai1,ai2,...,aim},其中下標i1,i2,...,im保持遞增,即新數列中的各個數之間依舊保持原數列中的先后順序,那么我們稱新的序列{ai1,ai2,...,aim}為原序列的一個子序列。若在子序列中,當下標ix > iy時,aix > aiy,那么我們稱這個子序列為原序列的一個遞增子序列。最長遞增子序列問題,就是在一個給定的原序列中,求得最長遞增子序列長度。

有序列{a1,a2,...,an},我們求其最長遞增子序列長度。按照遞推求解的思想,我們用F[i]代表若遞增子序列以ai結束時它的最長長度。當 i 較小,我們容易直接得出其值,如 F[1] = 1。那么,如何由已經求得的 F[i]值推得后面的值呢?假設,F[1]到F[x-1]的值都已經確定,注意到,以ax 結尾的遞增子序列,除了長度為1的情況,其它情況中,ax都是緊跟在一個由 ai(i < x)組成遞增子序列之后。要求以ax結尾的最長遞增子序列長度,我們依次比較 ax 與其之前所有的 ai(i < x), 若ai小於 ax,則說明ax可以跟在以ai結尾的遞增子序列之后,形成一個新的遞 增子序列。又因為以ai結尾的遞增子序列最長長度已經求得,那么在這種情況下,由以 ai 結尾的最長遞增子序列再加上 ax 得到的新的序列,其長度也可以確定,取所有這些長度的最大值,我們即能得到 F[x]的值。特殊的,當沒有ai(i < x)小 於ax, 那么以 ax 結尾的遞增子序列最長長度為1。 即F[x] = max{1,F[i]+1|ai<ax && i<x};

例如序列{1,4,3,2,6,5}的最長遞增子序列長度的所有F[i]為:

F[1] (1) F[2](4) F[3](3) F[4](2) F[5](6) F[6](5)
1 2 2 2 3 3

總結一下,求最長遞增子序列的遞推公式為:

F[1] = 1;

F[i] = max{1,F[j]+1|aj<ai && j<i}

我們可以根據遞推公式將算法實現

#include <iostream>
using namespace std;
const int MAXSIZE = 10;
const int MIN = 0;
int arr[] = { 1, 4, 3, 2, 6, 5 };
int F[MAXSIZE];
int main()
{
    int maxLen = MIN;
    memset(F, 0, MAXSIZE);
    F[0] = 1;
    for (int i = 1; i < 6; i++)
    {
        for (int j = 0; j < i; j++)
        {
            if (arr[i] > arr[j] && maxLen < F[j])
            {
                maxLen = F[j];
            }
        }

        F[i] = maxLen + 1;
    }

    for (int k = 0; k < 6; k++)
        cout << F[k] << ' ';
    cout << endl;
}


免責聲明!

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



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