POJ 2533 Longest Ordered Subsequence

Longest Ordered Subsequence
Time Limit: 2000MS Memory Limit: 65536K
Total 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

7
1 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值