• 求最长不下降子序列++


    【题目描述】

    设有由n(1n200)n(1≤n≤200)个不相同的整数组成的数列,记为:b(1)b(2)b(n)b(1)、b(2)、……、b(n)若存在i1<i2<i3<<iei1<i2<i3<…<ie 且有b(i1)b(i2)b(ie)b(i1)≤b(i2)≤…≤b(ie)则称为长度为e的不下降序列。程序要求,当原数列出之后,求出最长的不下降序列。

    例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一个长度为7的不下降序列,同时也有7 ,9,16,18,19,21,22,63组成的长度为8的不下降序列。

    【输入】

    第一行为n,第二行为用空格隔开的n个整数。

    【输出】

    第一行为输出最大个数max(形式见样例);

    第二行为max个整数形成的不下降序列,答案可能不唯一,输出一种就可以了,本题进行特殊评测。

    【输入样例】

    14
    13 7 9 16 38 24 37 18 44 19 21 22 63 15

    【输出样例】

    max=8
    7 9 16 18 19 21 22 63


    再加上一问,求当有多少种方案得到最长不下降子序列


    思路:单纯的求最长不下降子序列的长度再熟悉不过,不必多说。关键是那两问如何解决?

    那就是另外开两个数组。首先,输出一种方案,开一个pre数组,用来记录前面的轨迹。比如说a[j]+1>l,那么更新,pre[i]=j(a[i]前面的数是a[j]),最后找到其中一个最大值,输出即可,详情见代码

    其次,求方案数,开一个g数组。如果l>f[i],那么说明到a[i]是要经过a[j]的,所以g[i]=g[j],同时更新,f[i]=l。如果l==f[i](也有可能是由l>f[i]得来的,也就是说如果l>a[i],要跑两个if),根据加法原理,两个都行,那么就相加,也就是g[i]+=g[j]

    由以上思路,简单写一下核心代码:

    for(int i=1;i<=n;i++)
    {
    f[i]=1;g[i]=1;pre[i]=0;//因为一个数本身算一个,所以f数组当然初始化为1.而选这个数肯定也至少有一种方案,因为无论如何都可以选。把pre数组初始化是为了在输出的时候用while
    for(int j=1;j<i;j++)
    {
    if(a[j]<=a[i])
    {
    int l=f[j]+1;
    if(l>a[i])
    {
    g[i]=0;//这里跟思路不太一样,让g[i]=0,因为当它等于0时,下一个if相加就相当于g[i]=g[j],如果将两个if倒过来,应该可以写成g[i]=g[j]
    a[i]=l;
    pre[i]=j;
    }
    if(l==a[i])
    {
    g[i]+=g[j];
    }
    }
    最后的话只要循环一遍f数组,找到最大的其中那个值,另开一个数组,因为pre数组是倒着的,比如说最大的那个值是第i位,那么用一个while,就是当pre数组不等于0的时候,使答案数组等于pre数组,pre数组=pre[pre]......然后答案数组编号++就可以了

    优化:

    假设a[i]>a[j],且f[i]<=f[j],那么a[i]就已经没有用了,比如说1,4,3,5,易得它们的最长上升子序列长度分别为1,2,2,3,其中4和3就是上升子序列长度一样,而且前面的数小于后面的数,这样前面的数就没有用了,可以删掉。这是什么原理呢,其实整体感知一下就可以:

    如果一个子序列的末尾数越小,那么可以接在它后面的上升的数就越多,也就是越有可能,如果能接在小的数后面,那也肯定能接在大的数后面,并且接在小数后面更优,所以就可以更新掉,核心代码如下:

    int z[233],f[233],a[233];//a数组和f数组还是原本的含义,新开的z数组的意思是编号,是位置,z[i]=j的含义就是以a[j]为结尾的最长不下降子序列长度为i
    int cnt=0//定义一个变量,含义就是当前最长不下降子序列的长度
    for(int i=1;i<=n;i++)
    {
    f[i]=1;//初始化
    (以下两行循环可以用二分优化,但是我不会......)
    for(int j=1;j<=cnt;j++)
    if(a[z[j]]<=a[i]) f[i]=max(f[i],j+1);//如果存储在以这个数为末尾不下降子序列长度为j的数小于等于当前的数,那么这个数为末尾的不下降子序列就应该是本身和j+1的最大值
    if(f[i]>cnt) cnt++,z[cnt]=i;//如果当前的不下降子序列长度已经超过了最大值,那么更新最大值,同时将末尾数存入数组
    else//如果没有超过
    {
    if(a[i]<a[z[f[i]]]) z[f[i]]=i;//如果当前的数比存储在长度为f[i]的数小的话,更新
    }
    }

  • 相关阅读:
    Mac下安装brew
    Mac下安装node.js
    Mac下mysql服务端密码重置及环境配置
    Mac配置jdk以及maven
    Mac下卸载jdk
    34个漂亮的应用程序后台管理界面(系列一)
    ViewState
    get和post
    无刷新 分页评论
    isPostBack原理
  • 原文地址:https://www.cnblogs.com/57xmz/p/12651837.html
Copyright © 2020-2023  润新知