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;
}

 

posted @ 2016-01-16 22:16  JoneZP  阅读(670)  评论(0编辑  收藏  举报