zoukankan      html  css  js  c++  java
  • 最长上升子序列 LIS

    最长上升子序列 (反正这个oj我做不了)

    洛谷:AT2827 LIS

     题解:

    1.DP(TLE)

     这是一道最为经典的完全用动态规划来解决的问题。

    ◦          设dp[i]为以a[i]为末尾的最长上升子序列的长度。

    ◦          最后的答案就是我枚举一下最长上升子序列的结束位置,然后取一个dp[i]最大值即可。

    ◦          问题是如何求这个数组?

    ◦          那我们回过头来想一想最开始说的动态规划的基本思想,从小的问题推出大的问题。

    ◦          假设我们知道了dp[1..(i-1)],我们怎么才能根据这些信息推出来dp[i]。

    ◦          再次强化一下定义:dp[i]表示以i结尾的最长上升子序列长度。

    ◦          我们只需要枚举这个上升子序列倒数第二个数是什么就好了。

    ◦          状态转移:dp[i]=max{ dp[j] | a[j]<a[i] && j<i } +1 ; (dp记录的是长度)

    ◦          之前的例子:

    ◦          A:{2 , 5  , 3 , 4 , 1 , 7 , 6}

    ◦          dp[1]=1;

    ◦          dp[2]=max{dp[1]}+1;

    ◦          dp[3]=max{dp[1]}+1;

    ◦          dp[4]=max{dp[1],dp[3]}+1;

    ◦          时间复杂度 O(n^2)。

    ◦          在这个问题的分析中,突破口?

    ◦          1:设计出了dp[1..n]这个可以储存以i结尾的子序列中最优的答案,这个状态表示。

    ◦          2:通过分析问题成功能将当前状态的最优值能过由之前状态转移出来。dp[i]=max{ dp[j] | a[j]<a[i] && j<i } +1 ,状态转移。

    >最长上升子序列核心代码

    ◦     设dp[i]为以a[i]为末尾的最长上升子序列的长度。

    ◦     状态转移:dp[i]=max{ dp[j] | a[j]<a[i] && j<i } +1 ;

    >下面是DP玩火TLE代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    const int maxn=1e5+10;
    int n,ans=0;
    int a[maxn],dp[maxn];
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
           a[i]=read();
        for(int i=1;i<=n;i++)
        {
            dp[i]=1;
            for(int j=1;j<i;j++)
               if(a[j]<a[i]&&dp[j]+1>dp[i])
                 dp[i]=dp[j]+1;
            ans=max(ans,dp[i]);
        }
        
        printf("%d",ans);
        
        return 0;
    }

    2.lower_bound优化

    我们可以设最长上升子序列的长度为len

    d[len]表示长度为len的最长上升子序列里最后一个数

    当然,边界条件为

    len=1

    d[len]=a[1]; 

    从第二个枚举所给序列的所有元素

    设当前为i

    当a[i]比d[len]大的时候,就加入到d数组,更新len和队尾

    否则,如果a[i]!=d[len]

    那就找到队列中第一个大于等于a[i]的数,用a[i]替代它,因为a[i]比原来的更有潜力形成一个新的最长上升子序列

    此处采用lower_bound优化,相当于一个二分查询,一次查询O(logn)

    但是如果用两层DP的话大多数是会直接TLE   O(n^2)

     >下面是lower_bound优化AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    const int maxn=1e5+10;
    int n,len=0;
    int a[maxn],d[maxn];
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
           a[i]=read();
        d[++len]=a[1];
        for(int i=2;i<=n;i++)
        {
            if(a[i]>d[len]) d[++len]=a[i];
            else d[lower_bound(d+1,d+len+1,a[i])-d]=a[i];  //返回一个迭代器 
        }
        
        printf("%d",len);
        
        return 0;
    }

     

  • 相关阅读:
    python:一个比较有趣的脚本
    opencv:图像模糊处理
    opencv:基本图形绘制
    opencv:摄像头和视频的读取
    C++:lambda表达式
    opencv:傅里叶变换
    opencv:创建滑动条
    opencv:通过滑动条调节亮度和对比度
    【源码】防抖和节流源码分析
    【css】最近使用的两种图标字体库
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/10797740.html
Copyright © 2011-2022 走看看