動態規劃之最長子序列問題

一個數的序列bi,當b1 < b2 < … < bS的時候,我們稱這個序列是上升的。
對於給定的一個序列(a1, a2, …, aN),我們可以得到一些上升的子序列(ai1, ai2, …, aiK),這裏1 <= i1 < i2 < … < iK <= N。
比如,對於序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。這些子序列中最長的長度是4,比如子序列(1, 3, 5, 8).
我們的任務,就是對於給定的序列,求出最長上升子序列的長度。(最長不上升子序列就是正相反唄。)

下面我們以最長上升子序列爲例研究。
其他非遞增(減)等一系列問題就是以此爲基礎啊,比較的時候改改條件就行啊!
看清題目要求!
遞增和不下降是不一樣的啊摔!

O(n²)算法

seq[i]表示輸入的第i個元素,seqlen[i]表示以第i個元素爲末位的最長子序列長度。
在seqlen數組裏選出最長,就是最長子序列長度啊。

O(nlogn)算法

arr[i]表示輸入的數組元素,ans[len]表示生成長度爲len時子序列的末位元素,len表示序列長度。
如果arr數組的新元素比ans數組的所有元素都大,把這個元素放在ans數組的最後,子序列長度+1;
如果arr數組的新元素比ans數組的最大元素小,比ans數組的其他元素小,那就用新元素替換掉這個最大元素。比如len=2時,ans[2]={1,5};若ans[i]即新元素爲3,那就替換掉5,使得ans[2]={1,3},以保證有更多元素加入到序列中來。
所以我們發現,我們插入這個數據是通過替換來實現的,因而我們可以通過二分查找快速找到要替換的元素,從而將時間複雜度降低到O(nlogn)。

來舉個栗子~
假設存在一個序列arr[1..9] = 2 1 5 3 6 4 8 9 7,可以看出來它的LIS長度爲5。
下面一步一步試着找出它。
我們定義一個序列ans,然後令 i = 1 to 9 逐個考察這個序列。
此外,我們用一個變量Len來記錄現在最長算到多少了
首先,把arr[1]有序地放到ans裏,令ans[1] = 2,就是說當只有一個數字2的時候,長度爲1的LIS的最小末尾是2。這時Len=1。

然後,把arr[2]有序地放到ans裏,令ans[1] = 1,就是說長度爲1的LIS的最小末尾是1,arr[1]=2已經沒用了,這時Len=1。

接着,arr[3] = 5,arr[3]>ans[1],所以令ans[1+1]=ans[2]=arr[3]=5,就是說長度爲2的LIS的最小末尾是5,很容易理解吧。這時候ans[1..2] = 1, 5,Len=2。

再來,arr[4] = 3,它正好夾在1,5之間,放在1的位置顯然不合適,因爲1小於3,長度爲1的LIS最小末尾應該是1,這樣很容易推知,長度爲2的LIS最小末尾是3,於是可以把5淘汰掉,這時候ans[1..2] = 1, 3,Len = 2。

繼續,arr[5] = 6,它在3後面,因爲ans[2] = 3, 而6在3後面,於是很容易可以推知ans[3] = 6, 這時ans[1..3] = 1, 3, 6, Len = 3 。

第6個, arr[6] = 4,它在3和6之間,於是我們就可以把6替換掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len=3。

第7個, arr[7] = 8,它很大,比4大,於是ans[4] = 8。Len=4。

第8個, arr[8] = 9,得到ans[5] = 9,Len繼續增大,L=5。

最後一個, arr[9] = 7,它在ans[3] = 4和ans[4] = 8之間,所以我們知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。

於是我們知道了LIS的長度爲5。

ATTENTION!這個1,3,4,7,9不是LIS(真正的LIS是1,3,4,8,9或2,5,6,8,9),它只是存儲的對應長度LIS的最小末尾。有了這個末尾,我們就可以一個一個地插入數據。

好啦,來個模板題→_→模板水題POJ 2533

Description

A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.

Input

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000

Output

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Input

7
1 7 3 5 9 4 8

Sample Output

4

O(n²)算法

#include<cstdio>
#include<algorithm>
const int MAX=1010;
using namespace std;
int seq[MAX];
int seqlen[MAX];
int main()
{
    int i,j,n;
    int m;
    int maxn,maxlen=1;
    while(~scanf("%d",&n))
    {
        for(i=1; i<=n; i++)
        {
            seqlen[i]=1;
            scanf("%d",&seq[i]);
        }
        for (i=2; i<=n+1; i++)
        {
            maxn=0;
            for (j=1; j<=i-1; j++)
            {
                if(seq[j]<seq[i]&&seqlen[j]>maxn)
                    maxn=seqlen[j];
            }
            seqlen[i]=maxn+1;
            maxlen=max(maxlen,seqlen[i]);
        }
        printf("%d\n",maxlen);
    }
    return 0;
}

O(nlogn)算法

#include<cstdio>
#include<iostream>
#include<cstring>
const int MAXN=1010;
int arr[MAXN],ans[MAXN],i;
int seek(int num,int len)
{
    int low=1,high=len;
    while(low<=high)
    {
        int mid=(low+high)/2;
        if(num>=ans[mid]) low=mid+1;
        else high=mid-1;
    }
    return low;
}
int lis(int n)
{
    ans[1]=arr[1];
    int len=1;
    for(i=2; i<=n; ++i)
    {
        if(arr[i]>ans[len])
            ans[++len]=arr[i];
        else
        {
            int pos=seek(arr[i],len);
            ans[pos] = arr[i];
        }
    }
    return len;
}
int main()
{
    int T;
    while(~scanf("%d",&T))
    {
        for(i=1; i<=T; ++i)
            scanf("%d",&arr[i]);
        printf("%d\n",lis(T));
    }
    return 0;
}

ps:
好幾天前看過的了,當時被韜神說的無地自容(雖然也沒說什麼○| ̄|_),現在序列還是心中的痛/(ㄒoㄒ)/~~
不過現在好幾分會了QAQ

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章