zoukankan      html  css  js  c++  java
  • 最长上升子序列(O(n^2)与O(nlogn)+二分)最长公共子序列

    最长上升子序列(LIS)

    最长上升子序列是最基本的dp问题,以前一直都只写过O(n^2)的解法,现在终于有时间整理一下了。

    把poj上的几道最长上升子序列的水题又重新做了一下,主要有163125333903

    方法一:O(n^2)

    dp[i]:表示处理到第i个位置,序列的最长上升子序列末尾为i的长度; a[]数组存储原序列

    dp[i] = max{dp[j]+1},a[i]>a[j],0≤j≤i

    方法二:O(nlogn)

    方法一中求dp[i]时需要O(n)的复杂度,其实我们最后只需要知道最大的dp[j]+1就可以了,所以如果能够维护一个单调的数组,从而即可实现二分查找。

    dp[]和a[]与方法一中具有同样意义,再添加一个maxv[]数组,maxv[l]表示包含的最长上升子序列长度为l时,末尾的最小的数的值,举个例子:

    a[]:      1、2、3、-1123、1

    dp[]:    1、2、3、1234、2

    处理完第N位最后的maxv就会是:-1、1、2、3,毋庸置疑,maxv肯定是递增的,而且找到最小的值就保证了对于固定长度l时,可以直接从存储在maxv中的数得到最优解(呃,不知道怎么说清楚了),maxv在求解dp的过程中也是要不断更新的。

    如果最后要输出解的情况的话,那么maxv中就不能简单的存储固定长度对应的原序列的最小值了,而要记录下编号,好以后利用pre数组递归回去,而此时满足单调的数组就不是maxv[i]与i的关系了,而是a[maxv[i]]与i的关系了,更新maxv数组时也要注意。

    不输出解(poj 3903):

    View Code

    输出解(没有找到题号,自己写的):

    View Code

    最长公共子序列(LCS)

    最长公共子序列的基本转移方程为:d[i][j] = max{d[i'][j']}+1, p[i] = q[j],i'>i,j'>j

    基本的典型题是POJ 1159,附代码

    View Code
     1 /*也可进一步用滚动数组优化*/
     2 
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<cstring>
     8 using namespace std;
     9 short dp[5010][5010];
    10 
    11 char s1[5010], s2[5010];
    12 int main(){
    13     int n, m, i, j, k;
    14     scanf("%d",&n);
    15     cin>>s1;
    16     for(i=0;i<n;i++){
    17         s2[i] = s1[n-1-i];
    18     }
    19     memset(dp,0,sizeof(dp));
    20 
    21     for(i=1;i<=n;i++){
    22         for(j=1;j<=n;j++){
    23             if(s1[i-1]==s2[j-1]){
    24                 dp[i][j] = dp[i-1][j-1] + 1;
    25             }
    26             else{
    27                 dp[i][j] = max(dp[i][j-1],dp[i-1][j]);
    28             }
    29         }
    30     }
    31     printf("%d\n",n-dp[n][n]);
    32     return 0;
    33 }

    据说,LIS也又O(nlogn)的做法,使用静态二叉树(黑书上又说),目前还不会

    另外,最长上升子序列(LCS)最长公共子序列(LIS)其实可以互相转换。

    LCS -> LIS:把序列排序后与原序列找最长公共子序列

    LIS -> LCS:设有序列A,B。记序列A中各个元素在B中的位子(降序排列),然后按在A中的位置依次列出然后求A的最长递增子序列。

    例如:
    A串位置             1 2 3 4                             B串位置:        1 2 3 4

                      A串: 4 3 5 2                                              B串: 2 5 4 3



    A串在B串--位置  3 4 2 1  因为B串已经顺序了,只要求出这行的最长递增子序列 就是最长公共子序列的长度了。
      例如:有A={a,b,a,c,x},B={b,a,a,b,c,a}则有a={6,3,2},b={4,1},c={5};x=/;(注意降序排列)

    然后按A中次序排出{a(6,3,2),b(4,1),a(6,3,2),c(5),x()}={6,3,2,4,1,6,3,2,5};对此序列求最长递增子序列即可

    不过这种转换好像没有太大的帮助

  • 相关阅读:
    Nhibernate 简单实例(一)
    Sql 行转列
    EasyUI TreeGrid 的使用
    MSMQ消息队列的简单使用
    实体类与DataTable互换
    给Config的appSettings节点赋值
    Angular js (2)
    Angular JS 入门
    用Aspose.Cells 导出为自定义格式的excel
    【多线程学习笔记整理】002_线程的停止、暂停、与yield
  • 原文地址:https://www.cnblogs.com/celia01/p/2611043.html
Copyright © 2011-2022 走看看