zoukankan      html  css  js  c++  java
  • 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
    ", dfs(n-1)+ 1);
                printf("%d
    ", 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
    ", 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
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    Java匹马行天下之一顿操作猛如虎,框架作用知多少?
    ztree树应用
    动态将ASPX生成HTML网页并将网页导出PDF
    实现图片向上不停的无限滚动效果简单代码
    简单的前端正则验证用户输入的数字是否合法
    eclipse出现jdk版本更新导致无法启动
    删除所有视图 删除所有存储过程
    删除所有表的数据
    要求必须全部重复的数据sql--想了半天才写出来的
    查询树节点下的所有子节点包括根节点
  • 原文地址:https://www.cnblogs.com/ZP-Better/p/5136497.html
Copyright © 2011-2022 走看看