zoukankan      html  css  js  c++  java
  • 线性DP LIS浅谈

    LIS问题

    什么是LIS?

    百度百科

    最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。

    怎么求LIS?

    O(n^2)做法

    具体做法是用两个for,状态转移方程为f[i]=max(f[i],f[j]+1)其中f数组为这个位置的LIS长度,然后用max找一下最长LIS即可

    代码

    for(int i=1;i<=n;i++)
      for(int j=1;j<i;j++)
      if(a[j]<a[i])
      f[i]=max(f[i],f[j]+1);
      for(int i=1;i<=n;i++)
      ans2=max(ans2,f[i]);
    

    其中也可以取等号

    O(nlogn)做法

    具体做法是用数组去维护LIS,然后如果遇到比他小的二分数组

    代码

    if(u[ans2]<a[i])
        u[++ans2]=a[i];
        else
        u[lower_bound(u+1,u+ans2+1,a[i])-u]=a[i];
    

    拓展定理(Dilworth定理)

    什么是Dilworth定理?

    百度百科

    反链是一种偏序集,其任意两个元素不可比;而链则是一种任意两个元素可比的偏序集。Dilworth定理说明,存在一个反链A与一个将序列划分为链族P的划分,使得划分中链的数量等于集合A的基数。当存在这种情况时,对任何至多能包含来自P中每一个成员一个元#### 素的反链,A一定是此序列中的最大反链。同样地,对于任何最少包含A中的每一个元素的一个链的划分,P也一定是序列可以划分出的最小链族。偏序集的宽度被定义为A与P的共同大小。

    另一种Dilworth定理的等价表述是:在有穷偏序集中,任何反链最大元素数目等于任何将集合到链的划分中链的最小数目。一个关于无限偏序集的理论指出,在此种情况下,一个偏序集具有有限的宽度w,当且仅当它可以划分为最少w条链。

    对于LIS的用途

    求LIS的个数就是求最长下降子序列的长度,注意其中的<之类的符号是取补集的,也就是说如果上面用的>那么反面就是<=

    完整代码(洛谷模板题 P1020 导弹拦截)

    O(nlogn)算法

    #include <bits/stdc++.h>
    using namespace std;
    int a[100005],u[100005],l[100005];
    bool cmp(int a,int b)
    {
      return a>b;
    }
    int main()
    {
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      int n=1;
      while(cin>>a[n]) n++;
      n--;
      int ans1=1,ans2=1;
      l[1]=u[1]=a[1];
      for(int i=2;i<=n;i++)
      {
        if(l[ans1]>=a[i])
        l[++ans1]=a[i];
        else
        l[upper_bound(l+1,l+ans1+1,a[i],cmp)-l]=a[i];
        if(u[ans2]<a[i])
        u[++ans2]=a[i];
        else
        u[lower_bound(u+1,u+ans2+1,a[i])-u]=a[i];
      }
      cout<<ans1<<" "<<ans2;
    }
    

    O(n^2)算法

    #include <bits/stdc++.h>
    using namespace std;
    int a[100010];
    int f[100010];
    int main()
    {
      int n=1;
      while(cin>>a[n])
      f[n++]=1;
      n--;
      int ans1,ans2;
      ans1=ans2=-1;
      for(int i=1;i<=n;i++)
      for(int j=1;j<i;j++)
      if(a[j]>=a[i])
      f[i]=max(f[i],f[j]+1);
      for(int i=1;i<=n;i++)
      ans1=max(ans1,f[i]);
      for(int i=1;i<=n;i++)
      f[i]=1;
      for(int i=1;i<=n;i++)
      for(int j=1;j<i;j++)
      if(a[j]<a[i])
      f[i]=max(f[i],f[j]+1);
      for(int i=1;i<=n;i++)
      ans2=max(ans2,f[i]);
      cout<<ans1<<" "<<ans2;
    }
    
  • 相关阅读:
    Oracle EBS 初始化用户密码
    Oracle EBS FND User Info API
    linux ERROR: ld.so: object '/lib/libcwait.so' from /etc/ld.so.preload cannot be preloaded: ignored.
    linux解压cpio.gz类型文件
    linux删除乱码文件
    linux使用man命令后退出
    linux字符图形界面
    Red Hat linux 如何增加swap空间
    Linux删除文件夹命令
    Linux本地无法登录,远程却可以登录
  • 原文地址:https://www.cnblogs.com/baccano-acmer/p/9960078.html
Copyright © 2011-2022 走看看