码迷,mamicode.com
首页 > 其他好文 > 详细

POJ:最长上升子序列

时间:2015-05-02 21:53:50      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

Title: 

http://poj.org/problem?id=2533

Description

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.

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
这个是经典的动态规划题,像我这种渣渣,连这个都要看好久,好吧,其实简单的DP还好,就是nlogn复杂度的,看了好久。嗯,但是呢,网上的那些代码都没有我写的简洁,好吧,这也是聊以自慰呢。。
思路(1): O(n^2)

令A[i]表示输入第i个元素,D[i]表示从A[1]到A[i]中以A[i]结尾的最长子序列长度。对于任意的0 <  j <= i-1,如果A(j) < A(i),则A(i)可以接在A(j)后面形成一个以A(i)结尾的新的最长上升子序列。对于所有的 0 <  j <= i-1,我们需要找出其中的最大值。

DP状态转移方程:

D[i] = max{1, D[j] + 1} (j = 1, 2, 3, ..., i-1 且 A[j] < A[i])

解释一下这个方程,i, j在范围内:

如果 A[j] < A[i] ,则D[i] = D[j] + 1

如果 A[j] >= A[i] ,则D[i] = 1

int main(){
    int a[SIZE];
    int d[SIZE];
    int n;
    cin>>n;
    for (int i = 0; i < n; i++)
        cin>>a[i];
    int m = INT_MIN;
    for (int i = 0 ;i < n; i++){
        d[i] = 1;
        for (int j = 0; j < i; j++){
            if (a[j] < a[i])
                d[i] = max(d[i],d[j]+1);
        }
        m = max(m,d[i]);
    }
    cout<<m<<endl;
    //system("pause");
}

(2)nlogn的解法。

重新定义下dp[i]

dp[i] 的意思是所有长度为i+1的LIS中末尾元素的最小值

那么最开始,dp[0] = a[0]

因为dp是一个有序数组,所以每次我们都去这个数组中寻找a[i]的位置,例如dp = {2,4,6},如果a[i] = 5,那么a[i]的位置应该是4~6之间,所以返回index = 2.怎么理解呢,dp[i]的定义!所以a[i] = 5,那么有两个长度的最小值都比a[i]小,那加入a[i],这个长度肯定就是3了,然后这个index=2,同时,比较5和6,我们要选择最小的值。我的搜索代码包含了边界的情况,因此,在主函数中就不需要判断。

int search(int * s, int t,int l, int r){
    while (l <= r){
        int m = (l + r)/2;
        if (s[m] == t){
            return m;
        }else if (s[m] < t){
            l++;
        }else{
            r--;
        }
    }
    return l;
}
int main(){
    int a[SIZE];
    int n;
    cin>>n;
    for (int i = 0 ; i < n; i++){
        cin>>a[i];
    }
    int stack[SIZE];
    
    fill(stack,stack+SIZE,INT_MAX);
    stack[0] = a[0];
    int cur_index = 1;
    for (int i = 1; i < n; i++){
        int j = search(stack,a[i],0,cur_index);
        stack[j] = min(stack[j],a[i]);
        if (j == cur_index)
            cur_index++;
    }
    cout<<cur_index;
    //system("pause");
}

 



POJ:最长上升子序列

标签:

原文地址:http://www.cnblogs.com/yxzfscg/p/4472491.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!