• 最长上升子序列的初步学习


    最长上升子序列 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;
    }
  • 相关阅读:
    JVM体系结构和工作方式
    ClassLoader工作机制
    Javac编译原理
    类与类之间的几种关系
    一周总结汇总_2016-09-04
    一周规划汇总_2016-09-04
    Java基础知识笔记(一:修饰词、向量、哈希表)
    控制反转IoC简介
    DBCP连接池简介
    Struts与Struts2的区别
  • 原文地址:https://www.cnblogs.com/01world/p/5762803.html
Copyright © 2020-2023  润新知