• 最长上升子序列(LIS)模板


    最长递增(上升)子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增(上升)子序列。

    考虑两个数a[x]和a[y],x>y且a[x]<a[y],且dp[x]=dp[y],当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y],这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[x]一样时,尽量选择更小的a[x].

        按dp[t]=k来分类,只需保留dp[t]=k的所有a[t]中的最小值,设d[k]记录这个值,d[k]=min{a[t](dp[t]=k)}。

        这时注意到d的两个特点(重要):

    1. d[k]在计算过程中单调不升;           

    2. d数组是有序的,d[1]<d[2]<..d[n]。

        利用这两个性质,可以很方便的求解:

    1. 设当前已求出的最长上升子序列的长度为len(初始时为1),每次读入一个新元素x:

    2. 若x>d[len],则直接加入到d的末尾,且len++;(利用性质2)

       否则,在d中二分查找,找到第一个比x小的数d[k],并d[k+1]=x,在这里x<=d[k+1]一定成立(性质1,2)。

    #include<stdio.h>
    #include<string.h>
    const int N=1111;
    int d[N];
    int bs(int a[],int l,int r,int key)
    {
        while(l<r)
        {
            int mid=((l+r)&1)+(l+r)>>1;
            if(a[mid]<key)
                l=mid;
            else
                r=mid-1;
        }
        if(a[l]>=key)   return l-1;
        return l;
    }
    int LIS(int a[],int n)
    {
        int i,tmp,len=1;
        d[1]=a[1];
        for(i=2;i<=n;i++)
        {
            if(d[len]<a[i])
                tmp=++len;
            else
                tmp=bs(d,1,len,a[i])+1;
            d[tmp]=a[i];
        }
        return len;
    }
    int main()
    {
        int a[10]={-1,2,3,1,5,9,8};
        int tmp=LIS(a,6);
        printf("%d
    ",tmp);
        for(int i=1;i<=tmp;i++)
            printf("%d ",d[i]);
        printf("
    ");
        return 0;
    }
    LIS

    这种算法的时间复杂度是O(nlogn),但是稍微难写了一点。下面的是O(n^2),容易编写。

     1 int LIS(int *a,int n)
     2 {
     3     int i,j,ans=-1;
     4     memset(dp,0,sizeof(dp));dp[1]=1;
     5     for(i=2;i<=n;i++)
     6     {
     7         for(j=1;j<i;j++)
     8         {
     9             if(a[i]>a[j])
    10             {
    11                 if(dp[j]+1>dp[i])
    12                     dp[i]=dp[j]+1;
    13             }
    14         }
    15     }
    16     for(int i=1;i<=n;i++)
    17         if(dp[i]>ans)
    18             ans=dp[i];
    19     return ans;
    20 }
    View Code

    参考文章:http://www.cppblog.com/mysileng/archive/2012/11/30/195841.html

  • 相关阅读:
    java并发编程(五)——线程池
    java并发编程(四)——无锁
    java并发编程(三)——java内存模型
    java并发编程(二)——加锁
    java并发编程(一)——进程与线程
    java中的异常和处理机制
    使用JDK自带的keytool工具生成证书
    JAVA 制作证书
    网络安全之证书相关概念
    maven之.lastUpdated文件
  • 原文地址:https://www.cnblogs.com/L-King/p/5322683.html
Copyright © 2020-2023  润新知