首页 > 其他 > 详细

最长上升子序列问题

时间:2015-09-29 14:49:12      阅读:119      评论:0      收藏:0      [点我收藏+]

 最长上升子序列问题

有一个长为n的数列请求出这个序列中最长的上升子序列的长度,上升子序列值的是对于任意的,都满足的子序列。

N的范围决定与算法的选择

1<=N<=10000

这个问题也被称为最长递增子序列(LIS)

首先建立递推关系:

定义

dp[i]:=以为末尾的最长递增子序列的长度

以结尾的上升子序列是:

只包含的子序列

在满足并且的以为结尾的上升序列末尾,追加后得到的子序列

这二者之一,就能得到如下的递推公式:

技术分享

代码:

 

//输入
int n;
int a[N];
int dp[N];

void solve()
{
    int res=0;
    for(int i=0; i<n; ++i)
    {
        dp[i]=1;
        for(int j=0; j<i; ++j) if(a[j]<a[i])
        {
            dp[i]=max(dp[i],dp[j]+1);
        }
        res=max(res,dp[i]);
    }
    printf("%d\n",res);
}</span>

此外还可以定义其他递推关系,前面我们利用DP求取针对最末位的元素的最长递增子序列,如果子序列的长度相同

那么最末位的元素较小的在之后会更有优势,所以可以考虑反过来用DP针对相同长度情况下最小的末位元素进行求解

dp[i]:=长度为的上升序列中末位元素的最小值(不存在的话为INF)

  用DP来更新这个数组:

最开始全部DP数组赋值INF ,然后由前到后逐个考虑数列的元素,对于每个,如果i==0,或者

的话,就用dp[i]=min(dp[i],)进行更新,最终找出使得dp[i]<INF的最大的i+1

就是结果,此方法为考虑进一步优化,首先dp数组中除INF之外是单调递增的,所以对于每个最多需要更新1次,对于更新位置可以进行二分搜索进行加速,复杂度O(nlogn)。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int b[N],c[N];
int num[N];
int ans[N];
int LIS1(const int *a,int n)
{
    b[1]=a[0];
    int len=1;
    for(int i=1; i<n; ++i)
    {
        int k=lower_bound(b+1,b+len+1,a[i])-b;
        if(k>len) len++;
        b[k]=a[i];
    }
    return len;
}
int LIS2(const int *a,int n)
{
    int len=1,Left,Right,mid;
    c[1]=a[0];    ///初始时,最大递增子序列长度为1的最末元素为a1
    for(int i=1; i<n; i++)
    {
        Left=1;   ///左边初始长度为1
        Right=len;///右边表示当前所求长度
        while(Left<=Right)///二分查找最末元素小于ai+1的长度最大的最大递增子序列;
        {
            mid=(Left+Right)/2;
            if(c[mid]<a[i]) Left=mid+1;
            else Right=mid-1;
        }
        c[Left]=a[i];///将长度为Left的最大递增子序列的当前最末元素置为ai+1;
        if(Left>len) len++;///更新当前最大递增子序列长度;
    }
    return len;
}

最长上升子序列问题

原文:http://blog.csdn.net/u013050857/article/details/48806097

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!