POJ 2533 - Longest Ordered Subsequence - [最長遞增子序列長度][LIS問題]

題目連接:http://poj.org/problem?id=2533c++

Time Limit: 2000MS Memory Limit: 65536Kspa

Descriptioncode

A numeric sequence of  ai is ordered if  a1 <  a2 < ... <  aN. Let the subsequence of the given numeric sequence ( a1a2, ...,  aN) be any sequence ( ai1ai2, ...,  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.

Inputblog

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

Outputip

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

Sample Inputci

7
1 7 3 5 9 4 8

Sample Outputelement

4

 

題意:get

給定長度爲 $N$ 的一串整數序列 $a[1 \sim N]$,求其最長上升子序列的長度。input

注意:子序列能夠不連續,要求嚴格單增。it

 

題解:

$O(n \log n)$ 解法——貪心+二分。

構建一個棧 $S$ 和一個變量 $top$ 表明棧頂位置,該棧的表明:棧中的第 $i$ 個數 $S[i]$,是序列 $a$ 中,長度爲 $i$ 的遞增子序列的末尾元素。

初始化 S[top=1]=a[1] ,即將第一個數字入棧;這很好理解,到目前爲止 $a[1]$ 本身是一個長度爲 $1$ 的遞增子序列。

遍歷 $a[ i = 2 \sim N ]$:每次對於 $a[i]$,找出棧 $S[1 \sim top]$ 中第一個大於等於 $a[i]$ 的數的位置 $pos$,若不存在則返回 $pos=top+1$。

這是因爲,若存在第一個大於等於 $a[i]$ 的數 $S[pos]$ ,說明對於長度爲 $pos$ 的遞增子序列,能夠用 $a[i]$ 代替掉其原來的末尾元素 $S[pos]$,這樣一來,依然是一個長度爲 $pos$ 的遞增子序列,並且該遞增子序列被進一步「加長」的潛力增長。而若是棧中不存在大於等於 $a[i]$ 的數,這說明我能夠在目前長度爲 $top$ 的遞增子序列後面加上一個 $a[i]$,那麼咱們就獲得了一個以 $a[i]$ 爲結尾的,長度爲 $top+1$ 的遞增子序列。

所以,咱們把 $S[pos]$ 更新爲 $a[i]$,而且嘗試更新棧的大小 if(pos>top) top=pos;  。

因爲棧 $S$ 中元素始終保持單調遞增(並且棧內元素互不相等),因此找 $S$ 中第一個大於等於 $a[i]$ 的數能夠使用二分查找。

 

AC代碼(在OpenJudge百練提交):

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;

int n;
vector<int> a;

int S[maxn],top;
int LIS(const vector<int>& a)
{
    S[top=0]=a[0];
    for(int i=0;i<a.size();i++)
    {
        int pos=lower_bound(S,S+top+1,a[i])-S;
        S[pos]=a[i], top=max(top,pos);
    }
    return top+1;
}

int main()
{
    cin>>n;
    while(n--)
    {
        int x; cin>>x;
        a.push_back(x);
    }
    cout<<LIS(a)<<endl;
}

PS.咱們能夠看到,求第一個大於等於 $a[i]$ 的數使用了lower_bound,相應的若是咱們使用upper_bound會怎麼樣呢?不難證實,咱們將會獲得最長不降低子序列的長度。

相關文章
相關標籤/搜索