POJ-2533最长上升子序列(DP+二分)(优化版)

Longest Ordered Subsequence

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 41944   Accepted: 18453

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

方法一:记忆化搜索

缺点:时间复杂度O(n^2)

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);
#define maxn 1100

int a[maxn];
int dp[maxn];
int dfs(int p)
{
    if(dp[p] != -1) return dp[p];
    int res = 0;
    for(int i = 0; i < p; i++)
        if(a[p] > a[i])
            res = max(res, dfs(i)+1);
    dp[p] = res;
    return res;
}
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        memset(dp, -1, sizeof dp);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        int pp = -1;
        for(int j = 0;  j < n; j++)
        {
            pp = max(pp, dfs(j)+1);

        }
            //printf("%d\n", dfs(n-1)+ 1);
            printf("%d\n", pp);
    }
    return 0;
}

方法二:dp+二分

其中low_bound 返回第一个大于它的数的下标。

缺点:无法保存每个以 a[i]结尾的最长上升子序列。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);
#define maxn 11000

int a[maxn];
int dp[maxn];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        int cnt = 0;
        //memset(dp, INF, sizeof dp);
        dp[cnt] = a[0];
        for(int i = 1; i < n; i++)
        {
            if(a[i] > dp[cnt])
            {
                dp[++cnt] = a[i];
            }
            else
            {
                int pos = lower_bound(dp,dp+cnt+1,a[i]) - dp;
                dp[pos] = a[i];
            }
        }
        printf("%d\n", cnt+1);
    }

    return 0;
}

方法三:dp+二分(优化版)

弥补了上面两种方法不足。时间复杂度为O(nlogn) 又能保存每个以a[i]结尾的最长上升子序列。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);
#define maxn 11000

int a[maxn];
int b[maxn];
int dp[maxn];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);

        memset(dp, 0, sizeof dp);
        memset(b, INF, sizeof b);
        for(int i = 0; i < n; i++)
        {
            int pos = lower_bound(b,b+n,a[i]) - b;
            dp[i] = pos+1;
            b[pos] = a[i];
        }
        int ans = -1;
        for(int  i = 0; i < n; i++)
            ans = max(ans, dp[i]);
        printf("%d\n", ans);
    }

    return 0;
}
时间: 2024-10-13 00:17:25

POJ-2533最长上升子序列(DP+二分)(优化版)的相关文章

Longest Ordered Subsequence POJ - 2533 最长上升子序列dp

题意:最长上升子序列nlogn写法 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int dp[1005]; 7 int a[1005]; 8 int main(){ 9 int n; 10 while(cin>>n){ 11 for(int i=0;i<n;i++){ 12

poj 3903 &amp; poj 2533 最长上升子序列(LIS)

最长上升子序列. 做这道题之前先做了2533,再看这道题,感觉两道题就一模一样,于是用2533的代码直接交, TLE了: 回头一看,数据范围.2533 N:0~1000:3903 N :1~100000. 原因终归于算法时间复杂度. 也借这道题学习了nlgn的最长上升子序列.(学习链接:http://blog.csdn.net/dangwenliang/article/details/5728363) 下面简单介绍n^2 和 nlgn 的两种算法. n^2: 主要思想:DP: 假设A1,A2..

[kuangbin带你飞]专题十二 基础DP1 N - Longest Ordered Subsequence POJ - 2533(最长上升子序列LIS)

N - Longest Ordered Subsequence POJ - 2533 题目链接:https://vjudge.net/contest/68966#problem/N 题目: 最长有序子序列如果a1 <a2 <... <aN,则排序ai的数字序列. 让给定数字序列(a1,a2,...,aN)的子序列为任何序列(ai1,ai2,...,aiK),其中1 <= i1 <i2 <... <iK <= N 例如,序列(1,7,3,5,9,4,8)具有有

Bridging signals POJ 1631(最长递增子序列dp)

原题 题目链接 题目分析 由题目知,如果能求出连接点的最长递增子序列,则可以把连接不在该序列中的点的线全部剪掉.而维护最长递增子序列可以用dp来做,考虑到相同长度的递增子序列末尾数字越小越好,可以这样定义dp,dp[i]长度为i的递增子序列的最小末尾值,初始化为INF,由于这个dp具有有序性,因此可以用二分来加快更新,每次遍历到值num[i],只需二分找出大于等于num[i]的更新之即可.最后从扫一遍dp数组即可得到最长长度. 代码 1 #include <iostream> 2 #inclu

最长上升子序列的二分优化

http://blog.csdn.net/wall_f/article/details/8295812 作者写的太好了,转载一下~ 我简单总结一下,我的理解. 最长上升子序列的转移方程:b[k]=max(max(b[j]|a[j]<a[k],j<k)+1,1); 其优化主要在求解当前最长长度是要查找前面的b数组中是否有最大的值,且当前期a[j]<a[k],因此就是要找小于当前值的最大值. 所以我们一般需要从1~k-1扫描一遍找到最大值,复杂度为o(n^2),耗时太长. 因此我们可以直接记

UVa 10534 Wavio Sequence (最长递增子序列 DP 二分)

Wavio Sequence  Wavio is a sequence of integers. It has some interesting properties. ·  Wavio is of odd length i.e. L = 2*n + 1. ·  The first (n+1) integers of Wavio sequence makes a strictly increasing sequence. ·  The last (n+1) integers of Wavio s

poj 2533 最长上升子序列

Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 39374   Accepted: 17315 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ...

poj之最长递增子序列

题目:POJ 2533   Longest Ordered Subsequence 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 &l

POJ 1631(最长上升子序列 nlogn).

~~~~ 由题意可知,因为左边是按1~n的顺序递增排列,要想得到不相交组合,左边后面的一定与相应右边后面的相连,如此一来, 就可以发现其实是一道最长上升子序列的题目,要注意的是N<40000,用n^2的算法一定会超时. 题目链接:http://poj.org/problem?id=1631 ~~~~ nlogn的算法在这里补充一下. 最长不下降子序列的O(nlogn)算法分析如下: 设 A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F [t]