• 最长下降/上升子序列问题


    最长下降/上升子序列

    开始的时钟永远为你的奋斗时刻准备着,只要你需要它
    这题目是经典的DP题目,也可叫作LIS(Longest Increasing Subsequence)最长上升子序列或者 最长不下降子序列。很基础的题目,有两种算法,复杂度分别为O(n*logn)和O(n^2) 。

    一.问题描述

    设有由n个不相同的整数组成的数列,记为:
    
    a(1)、a(2)、……、a(n)且a(i)<>a(j) (i<>j)
    
    例如3,18,7,14,10,12,23,41,16,24。
    
    若存在i1<i2<i3< … < ie 且有a(i1)<a(i2)< …
    
    <a(ie)则称为长度为e的不下降序列。如上例中3,18,23,24就是一个长度为4的不下降序列,同时也有3,7,10,12,16,24长度为6的不下降序列。程序要求,当原数列给出之后,求出最长的不下降序列。
    
    二.算法分析
    
    (一)。根据动态规划的原理,由后往前进行搜索。
    
    1·对a(n)来说,由于它是最后一个数,所以当从a(n)开始查找时,只存在长度为1的不下降序列;
    
    2·若从a(n-1)开始查找,则存在下面的两种可能性:
    
    ①若a(n-1)<a(n)则存在长度为2的不下降序列a(n-1),a(n)。
    
    ②若a(n-1)>a(n)则存在长度为1的不下降序列a(n-1)或a(n)。
    
    3·一般若从a(i)开始,此时最长不下降序列应该按下列方法求出:
    

    在a(i+1),a(i+2),…,a(n)中,找出一个比a(i)大的且最长的不下降序列,作为它的后继。倒推公式为

    F(I)=MAX{F(I+K)}+1

    F[I]:表示以第I个位置为起点的最长不下降序列的长度。

    K的选择范围:a(I+k)>a(i) I+k≦n

    最后从F[1]到F[N]中选取最大的即为最优解

    当然也可以采用顺推的方法,顺推公式为

    F(I)=MAX{F(I-K)}+1

    F[I]:表示以第I个位置为终点的最长不下降序列的长度。

    K的选择范围:a(I-k)<a(i) I-k≧1

    最后从F[1]到F[N]中选取最大的即为最优解

    4·为算法上的需要,定义一个数组(倒推法)
    
    整数类型二维数组d(N,3)
    
    d(I,1)表示点a(i)
    
    d(I,2)表示从I位置到达N的最长不下降序列长度
    
    d(I,3)表示从I位置开始最长不下降序列的下一个数字的位置,以便打印。
    
    初始化:
    
    FOR I = 1 TO N
    
    INPUT #1, D(I, 1)
    
    D(I, 2) = 1
    
    D(I, 3) = 0
    
    NEXT I
    

    A.O(n^2)算法分析如下:

    (a[1]...a[n] 存的都是输入的数)
    1、对于a[n]来说,由于它是最后一个数,所以当从a[n]开始查找时,只存在长度为1的不下降子序列;
    2、若从a[n-1]开始查找,则存在下面的两种可能性:
    (1)若a[n-1] < a[n] 则存在长度为2的不下降子序列 a[n-1],a[n];
    (2)若a[n-1] > a[n] 则存在长度为1的不下降子序列 a[n-1]或者a[n]。
    3、一般若从a[t]开始,此时最长不下降子序列应该是按下列方法求出的:
    在a[t+1],a[t+2],...a[n]中,找出一个比a[t]大的且最长的不下降子序列,作为它的后继。
    4、为算法上的需要,定义一个数组:
    int d[n][3];
    d[t][0]表示a[t];
    d[t][1]表示从i位置到达n的最长不下降子序列的长度;
    d[t][2]表示从i位置开始最长不下降子序列的下一个位置。
    实现代码如下:

    include
    using namespace std;
    int main(void)
    {
    int i,j,n,a[100],b[100],max;
    while(cin>>n)
    {
    for(i=0;i<n;i++)
    cin>>a[i];
    b[0]=1;//初始化,以a[0]结尾的最长递增子序列长度为1
    for(i=1;i<n;i++)
    {
    b[i]=1;//b[i]最小值为1
    for(j=0;j<i;j++)
    if(a[i]>a[j]&&b[j]+1>b[i])
    b[i]=b[j]+1;
    }
    for(max=i=0;i<n;i++)//求出整个数列的最长递增子序列的长度
    if(b[i]>max)
    max=b[i];
    cout<<max<<endl;
    }
    return 0;
    }

    显然,这种方法的时间复杂度仍为o(n^2);
    例题:NOIP1999(dp入门经典)
    题意:某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

    输入格式输入数据为两行,

    第一行为导弹的数目N(n<=1000)

    第二行导弹依次飞来的高度,所有高度值均为不大于30000的正整数。

    输出格式输出只有一行是这套系统最多能拦截的导弹数和要拦截所有导弹最少要配备这种导弹拦截系统的套数。两个数据之间用一个空格隔开.

    样例输入

    8
    389 207 155 300 299 170 158 65

    样例输出

    6 2

  • 相关阅读:
    Dynamics AX 2012 R2 配置E-Mail模板
    Dynamics AX 2012 R2 设置E-Mail
    Dynamics AX 2012 R2 为运行失败的批处理任务设置预警
    Dynamics AX 2012 R2 耗尽用户
    Dynamics AX 2012 R2 创建一个专用的批处理服务器
    Dynamics AX 2012 R2 创建一个带有负载均衡的服务器集群
    Dynamics AX 2012 R2 安装额外的AOS
    Dynamics AX 2012 R2 将系统用户账号连接到工作人员记录
    Dynamics AX 2012 R2 从代码中调用SSRS Report
    Dynamics AX 2012 R2 IIS WebSite Unauthorized 401
  • 原文地址:https://www.cnblogs.com/Keven02/p/6431343.html
Copyright © 2020-2023  润新知