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;
    }
  • 相关阅读:
    Python封装发送信息到钉钉群
    centos 7.6 安装php70
    小米5s plus刷机
    centos 7 安装webmin
    交易开拓者旗舰版(TB旗舰版)软件升级中如何迁移用户数据
    centos 7.6 修改vim配色方案
    centos 7.0 读写ntfs分区
    centos iptables 数据转发
    centos 7.6 配置VNC
    win下maridb 10.1.8下主从复制配置
  • 原文地址:https://www.cnblogs.com/ZP-Better/p/5136497.html
Copyright © 2011-2022 走看看