zoukankan      html  css  js  c++  java
  • 最长上升子序列的初步学习

    最长上升子序列 LIS

    对于求解LIS的可以用O(n^2)的复杂度求解:
    设d[i]为以i为结尾的最长上升子序列的长度,则d[i]=max{0,d[j] }+1 (j< i)

    有时数据范围比较大,这时就要考虑O(nlogn)的算法了:
    网上很多博客已经给出了很详细的说明,我只给出实现的代码:

       /*
       d[i]为以i为结尾的最长上升子序列的长度
       g保存伪最长上升子序列
       */
        for(int i=1;i<=n;i++)g[i]=INF;
        for(int i=0;i<n;i++){
            int k=lower_bound(g+1,g+n+1,a[i])-g;
            d[i]=k;
            g[k]=a[i];
        }

    上面的代码说g保存伪最长上升子序列 ,这句的意思是g中的最长上升子序列并不是真正的最长上升子序列,因为g保存的是更新d值的过程中用来维护最优解的(不知道这样说合适吗QAQ),如果要想打印最长上升子序列还得用O(n^2)的算法。

    来道题目:http://acm.hdu.edu.cn/showproblem.php?pid=1257
    HDU 1257 最少拦截系统
    题意:
    导弹拦截系统,每次发射高度不高于前一发,问最少需要几套?
    分析:
    题目相当于要求一个最长上升子序列,可能一下子想不出来,建议用模拟的想法来做这道题,可能就会知道怎么做了。我做这题的时候没看出是最长上升子序列,是先按模拟+贪心(实际上就是LIS nlogn的实质)的思想去做的,写完后发现跟LIS一样!
    来点提示:
    看一下样例吧:8 389 207 155 300 299 170 158 65
    389 207 155 65
    300 299 170 158
    显然需要两组,我们模拟的时候,第一次是389,然后第二次是207,这时207覆盖掉389就行,然后155,,155覆盖掉207 。300不能覆盖155,所以另起一组,然后299。。。就这样,一直到最后。注意一点,最后那个65为什么在第一组而不是第二组呢?理解了这点那么这个算法就明白了!!

    const int N=1e5+2;
    int a[N];
    int main()
    {
        int n,t;
        while(~scanf("%d",&n)){
            int cnt=1;
            scanf("%d",&a[0]);
            for(int i=1;i<n;i++){
                scanf("%d",&t);
                if(a[cnt-1]<t)a[cnt++]=t;
                else{
                    int k=lower_bound(a,a+cnt,t)-a;
                    a[k]=t;
                }
            }
            cout<<cnt<<endl;
        }
        return 0;
    }

    O(nlogn)的算法是不是足够完美呢?并不是!因为它无法得到真正的最长上升子序列!对于打印解的题目,肯定是O(n^2)的!

    来道题目:http://acm.hdu.edu.cn/showproblem.php?pid=1160
    HDU 1160 FatMouse’s Speed
    题意:
    老鼠要两个参数,w体重,s速度,w按照升序,s按照降序,求最长的排列?
    分析:
    显然是道最长上升子序列类型的题目,因为要打印解,那么肯定是O(n^2),那么按照w排完序后,在按照O(n^2)的状态转移方程去求解即可。

    const int N=1e5+2;
    struct data{
        int w,s,id;
        bool operator < (const data& rhs) const {
            if(w==rhs.w)return s>rhs.s;
            return w<rhs.w;
        }
    }a[N];
    int res[N],d[N],pre[N];
    int main()
    {
        memset(pre,-1,sizeof(pre));
        int n=0;
        while(~scanf("%d%d",&a[n].w,&a[n].s))a[n].id=n+1,n++;
        sort(a,a+n);
        int pos=0,maxn=0;
        for(int i=0;i<n;i++){
            d[i]=1;
            for(int j=0;j<i;j++)
            if(a[j].w<a[i].w&&a[j].s>a[i].s&&d[i]<d[j]+1){
                pre[i]=j;d[i]=d[j]+1;
            }
            if(maxn<d[i]){
                maxn=d[i];
                pos=i;
            }
        }
        int cnt=0;
        while(pos!=-1){
            res[cnt++]=pos;
            pos=pre[pos];
        }
        printf("%d
    ",maxn);
        while(cnt>0){
            cnt--;
            printf("%d
    ",a[res[cnt]].id);
        }
        return 0;
    }
  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/01world/p/5762803.html
Copyright © 2011-2022 走看看