POJ 2533 Longest Ordered Subsequence

来源:互联网 发布:windows to go u盘要求 编辑:程序博客网 时间:2024/06/05 07:13

Longest Ordered Subsequence
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 40236 Accepted: 17700

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

71 7 3 5 9 4 8

Sample Output

4

Source

Northeastern Europe 2002, Far-Eastern Subregion

题目链接 POJ 2533

分析:

求最长上升子序列

dp[ i ] : 以下标为 i 的元素结尾的最长上升子序列的长度

状态转移: dp[ i ] = max(dp[ i ], dp[ j ] + 1)  (i > j, num[ i ] > num[ j ])

代码:

#include <cstdio>#include <iostream>using namespace std;int main(){    int n, dp[1010], num[1010];    int Max = 0;    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%d", &num[i]);    for (int i = 0; i < n; i++)    {        dp[i] = 1;              //初始化为 1        for (int j = 0; j < i; j++)        {            if(num[i] > num[j])                dp[i] = max(dp[i], dp[j] + 1);  //状态转移        }        Max = max(Max, dp[i]);    }    printf("%d\n", Max);    return 0;}

注意了,这个代码的时间复杂度为 O(n^2),不过很侥幸这一题没有TLE

以防万一,下面介绍一种 O(nlog2^n) 的方法,类似于二分查找

que 为一个递增序列。我们将题目中所给的序列依次插入到 que 中

每次插入之后 que 的性质不变,即它仍然是递增序列

例如:原序列为 1 2 3 5 8

插入4之后 1 2 3 4 8

假设要在 que 中插入 x ,要插入的位置就是从左向右遍历 que,第一个大于或等于 x 的元素

的位置

当然我们不遍历查找这个位置(太笨,时间效率不高),用二分查找(因为序列永远有序,并且效率贼高)

最后求得的 que 的长度就是答案

代码:

#include <cstdio>#include <iostream>using namespace std;int num[1010], que[1010];int main(){    int n;    scanf("%d", &n);    for (int i = 0; i < n; i++)        scanf("%d", &num[i]);    int tail = 0;       //队列尾部的指针    que[0] = -1;        //初始化小于所给的所有数据    for (int i = 0; i < n; i++)    {        if (num[i] > que[tail])     //大于最大的元素,直接在最后插入        {            que[++tail] = num[i];        }        else                //二分查找要插入的位置        {            int L = 1, R = tail;            while (L <= R)            {                int M = (L + R) >> 1;   //二进制的右移,相当于(L + R) / 2                if (num[i] > que[M]) L = M + 1;                else R = M - 1;            }            que[L] = num[i];        //L 就是查找到的位置        }    }    printf("%d\n", tail);    return 0;}

最后放个大招,STL 中的 lower_bound(),原理和上面的代码差不多

代码:

#include <cstdio>#include <iostream>#include <algorithm>using namespace std;const int INF = 0x7fffffff;int num[1010], que[1010];int main(){    int n, Max = 0;    scanf("%d", &n);    for (int i = 0; i < n; i++)        scanf("%d", &num[i]);    for (int i = 0; i < n; i++) //初始化int最大值,因为要从左向右查找第一个大于等于...        que[i] = INF;    for (int i = 0; i < n; i++)    {        int k = lower_bound(que, que + n, num[i]) - que;    //要插入的位置        que[k] = num[i];        Max = max(Max, k);    }    printf("%d\n", Max + 1);    return 0;}

STL大法好,不过最好还是自己知道原理,能实现。


0 0
原创粉丝点击