1. for(int i = 1;i <= n;i++)
  2. {
  3. int dpmax = 0;
  4. for(int j = 1;j <= m;j++)
  5. {
  6. dp[i][j] = dp[i-1][j];
  7. if(a[i] > b[j] && dpmax < dp[i-1][j])dpmax = dp[i-1][j];
  8. if(a[i] == b[j])dp[i][j] = dpmax + 1;
  9. ret = max(ret,dp[i][j]);
  10. }
  11. }

LCS最长公共子序列:

状态方程是dp[i][j]——并未定义必须以谁谁谁结尾,就是代表a序列从1-i,b序列从1-j的最长公共部分的长度 状态转移:1->当a[i] == b[j]的时候很明显dp[i][j]的值==dp[i-1][j-1] + 1

2->当a[i] != b[j]的时候,要去寻找最优解,肯定是max(dp[i-1][j],dp[i][j-1])这两个解肯定比dp[i-1][j-1]优啊

  1. for(int i = 1;i <= la;i++)
  2. {
  3. for(int j = 1;j <= lb;j++)
  4. {
  5. if(a[i-1] == b[j-1])
  6. {
  7. dp[i][j] = dp[i-1][j-1] + 1;
  8. }
  9. else
  10. {
  11. dp[i][j] = max(dp[i-1][j],dp[i][j]);
  12. dp[i][j] = max(dp[i][j-1],dp[i][j]);
  13. }
  14. }

LCS还是很好理解的,想一想就能自己实现了

LIS最长上升子序列 状态方程:dp[i] 表示该序列以a[i]为结尾的最长上升子序列的长度 状态转移最外层的循环遍历的是1 - n-1的数据(i)内层的数据遍历的是j(j < i)寻找子最长上升序列长度中能把a[i]加进入的最长序列也就是如果a[j] < a[i] dp[i] = max(dp[j] + 1,dp[i])

  1. for(int i = 1;i < N;i++)
  2. {
  3. for(int j = 0;j < i;j++)
  4. {
  5. if(hi[j] < hi[i])
  6. {
  7. dp[i] = max(dp[j] + 1,dp[i]);
  8. }
  9. }
  10. if(dp[i] > ret)ret = dp[i];
  11. }

优化时间复杂度

下面的LIS的O(nlogn)转自于http://hi.baidu.com/fandywang_jlu/item/da673a3d83e2a65980f1a7e1

一、算法思想

算法还是容易想到的,两重循环DP即可。不过如果数据规模最大可以达到几十万甚至更大,经典的O(n^2)的动态规划算法明显会超时。我们需要寻找更好的方法来解决是最长上升子序列问题。以下以最长递增子序列为例进行说明:

   先回顾经典的O(n^2)的动态规划算法,设A[i]表示序列中的第i个数,F[i]表示从1到i这一段中以i结尾的最长上升子序列的长度,初始时设 F[i] = 0(i = 1, 2, ..., len(A))。则有动态规划方程:F[i] = max{1, F[j] + 1} (j = 1, 2, ..., i - 1, 且A[j] < A[i])。

  现在,我们仔细考虑计算F[i]时的情况。假设有两个元素A[x]和A[y],满足(1)y < x < i (2)A[x] < A[y] < A[i] (3)F[x] = F[y]

  此时,选择F[x]和选择F[y]都可以得到同样的F[i]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢?

  很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[i-1]这一段中,如果存在A[z],A[x] < A[z] < A[y],则与选择A[y]相比,将会得到更长的上升子序列。

  再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[i] = k的所有A[i]中的最小值。设D[k]记录这个值,即D[k] = min{ A[i] } ( F[i] = k )。

  注意到D[]的两个特点:

  (1) D[k]的值是在整个计算过程中是单调不上升的。//此处需要特别注意!!!关键之所在!

  (2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。

利 用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[i]与D[len],若A[i] > D[len],则将A[i]接在D[len]后将得到一个更长的上升子序列,len = len + 1,D[len+1] = A[i];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[i].令k = j + 1,则有D[j] < A[i] <= D[k],将A[i]接在D[j]后将得到一个更长的上升子序列,同时更新D[k] = A[i].最后,len即为所要求的最长上升子序列的长度。

  在上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于 共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),与原来的算法相比没有任何进步.但是由于D[]的特 点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法的时间复杂度下降为O(nlogn),有了非常显著的提高.需要注意的 是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列.

这个算法还可以扩展到整个最长子序列系列问题,整个算法的难点在于二分查找的设计,需要非常小心注意.

  1. while(p--)
  2. {
  3. scanf("%d",&num);
  4. if(num > dp[tot])
  5. {
  6. dp[++tot] = num;
  7. }
  8. else
  9. {
  10. int idx = binary_search_index(1,tot,num);
  11. dp[idx] = num;
  12. }
  13. }

idx寻找的就是需要更替的值的下标,二分有许多类似的写法,都可行,我用的是我理解的比较好的那个

  1. int binary_search_index(int left,int right,int num)
  2. {
  3. while(left < right)
  4. {
  5. int mid = (left + right) / 2;
  6. if(num <= dp[mid])right = mid;
  7. else left = mid + 1;
  8. }
  9. return left;
  10. }

在这里,我要说一下我对len最后就是最长上升子序列长度的理解

首先,如果给出的序列一开始就是上升序列的化例如1,3,5,7,那么dp中的值就会说1,3,5,7;如果在这些数后面加上2,4,6,那么dp中的值就是1,2,3,4,它每次存的都是最小的,你会发现3,5,7和2,4,6之间!打乱顺序后,dp的值都不会变(3,5,7的先后顺序不变)那么你加上一个8,会改变len的值,你加上一个2就不会改变,为什么加2不会改变呢,因为数太少,前面所得到的len是由1,2,4,6进行维护的,其实你加上一个7就可以改变最后的结果,但是你加上一个5,一个5!只会改变维护的值,这是侯维护的就是1,2,4,5,你再加个6就可以改变结果了。 再说一点,之所以dp中的值并不一定是正确的lis,是因为(还是以1 3 5 7 2 4 6为例,dp:1,2,4,6)你再加一个3就会变成1,2,3,6——他是用于维护的,谁染顺序打断了,就仿佛代表,如果你想改变len的值,就必须加入一个比6大的数,或者2个比3大且比6小的数,3个比2大比3小的数……事实证明,最长上升子序列长度的改变就是因为此,打乱了原有的顺序,是为了更好的维护len的值!!!

LCIS两者的结合最长上升公共子序列

状态方程dp[i][j]表示以b[j]为结尾的最长上升公共子序列的长度(这是一个难点,面对新的题目,怎么才能快速的找到这个最优的状态方程呢??)

状态转移:如果a[i] != b[j]的化,很好我必须要有b[j]但是a[i]不能匹配,那么我就去看dp[i-1][j]去吧

如果a[i] == b[j] 那么我就得再 dp[i-1][k]k是1-j-1,中找到最长的而且还得能让b[j]加到其末尾的值 这样就可以写出差不多n**3的算法了,很不完美,一定要进行优化,只能再a[i] == b[j]得时候做文章,看看n**3得算法

  1. for(i = 1; i <= n; i++)
  2. {
  3. for(j = 1; j <= m; j++)
  4. {
  5. f[i][j] = f[i-1][j]; // if(a[i] != b[j])
  6. if(a[i] == b[j])
  7. {
  8. int MAX = 0;
  9. for(k = 1; k <= j-1; k++) if(b[j] > b[k]) //枚举最大的f[i-1][k]
  10. {
  11. MAX = max(MAX, f[i-1][k]);
  12. }
  13. f[i][j] = MAX+1;
  14. }
  15. }
  16. }

你再遍历k得时候就发现,当我遍历j到a[i] == b[j]得时候,前面j得遍历就是我的k得遍历,所以我就可以设法节省了,k遍历得目的就是找一个最大值——他满足b[j] > b[k],所以我就设定一个dpmax用a[i]表示与a[i]相等得b[j],没有怎么办,没有就用不到dpmax啊

LCIS记录最长上升公共子序列得数据~~

LCS,LIS,LCIS学习的更多相关文章

  1. LCS/LIS/LCIS 模板总结

    /************************* LCS/LIS/LCIs模板总结: *************************/ /*************************** ...

  2. LCS,LIS,LCIS

    网站:CSUST 8月3日(LCS,LIS,LCIS) LCS:      以下讲解来自:http://blog.csdn.net/yysdsyl/article/details/4226630 [问 ...

  3. hdu 1423(LCS+LIS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1423 好坑啊..还有公共串为0时的特殊判断,还有格式错误..看Discuss看知道除了最后一组测试数据 ...

  4. 【ACM程序设计】动态规划 第二篇 LCS&LIS问题

    动态规划 P1439 [模板]最长公共子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 给出 1,2,-,n 的两个排列 P1 和 P2 ,求它们的最长公共子序列. ...

  5. LCS(记录路径)+LIS+LCIS

    https://blog.csdn.net/someone_and_anyone/article/details/81044153 当串1 和 串2 的位置i和位置j匹配成功时, dp[i][j]=d ...

  6. LCS+LIS

    #include<iostream> #include<string> using namespace std; string a,b; ][]; int main() { w ...

  7. Uva 10635 - Prince and Princess LCS/LIS

    两个长度分别为p+1和q+1的由1到n2之前的整数组成的序列,每个序列的元素各不相等,两个序列第一个元素均为1.求两个序列的最长公共子序列 https://uva.onlinejudge.org/in ...

  8. 【LCS,LIS】最长公共子序列、单调递增最长子序列

    单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4   输入 ...

  9. 最长上升序列 LCS LIS

    子序列问题 (一)一个序列中的最长上升子序列(LISLIS) n2做法 直接dp即可: ;i<=n;i++) { dp[i]=;//初始化 ;j<i;j++)//枚举i之前的每一个j ) ...

随机推荐

  1. Numpy随机数

    Numpy随机数 np.random随机数子库 1: 基本函数 .rand(d0,d1,..dn):创建d0-dn维度的随机数数组,浮点数,范围从0-1,均匀分布 .randn(d0,d1,..dn) ...

  2. sql server 数据库学习

    http://m.blog.csdn.net/anxpp/article/details/51295020

  3. JPA报错, PersistenceException_Unable to build Hibernate SessionFactory

    javax.persistence.PersistenceException: [PersistenceUnit: TestJPA] Unable to build Hibernate Session ...

  4. SVN的基本操作

    右键SVN Commit 提交成功了,我们把SVN的服务器端刷新一下 所有的操作如果只是删除本地的文件都不会影响服务器端的文件,除非右键SVN Commit删除文件或者是新增文件才会对服务器端的仓库里 ...

  5. python3 回顾笔记1

    http://www.runoob.com/python3/python3-tutorial.html这个网址,可以学习python3的基础语法. 1. 单引号和双引号意义完全相同.用r可以限制转义符 ...

  6. python的进程间的数据交互

    #先来看下如何实现多进程 # multiprocessing 这个是python的多进程的模块,我们会用到这个模块的很多方法 from multiprocessing import Process i ...

  7. Devexpress系列一 之 ChartControl 柱形图BarSideBySideSeries2D

    这一篇是讲的是简单的柱形图, 柱形图运行效果如下图: 新建WPF窗体应用程序后(WPF用户控件也可以),工程引用DevExpress.Xpf.Charts.v17.1.dll, 在XAML头部引用名称 ...

  8. 3.说一下你了解的弹性FLEX布局.

    页面布局一直都是web应用样式设计的重点 我们传统的布局方式都是基于盒模型的 利用display.position.float来布局有一定局限性 比如说实现自适应垂直居中 随着响应式布局的流行,CSS ...

  9. windows,phalcon工具的安装使用

    一.使用工具之前,必须安装phalcon的扩展,也就是php_phalcon.dll动态链接库 phalcon官方地址:https://github.com/phalcon/cphalcon/rele ...

  10. 【转】MEF程序设计指南三:MEF中组合部件(Composable Parts)与契约(Contracts)的基本应用

    按照MEF的约定,任何一个类或者是接口的实现都可以通过[System.ComponentModel.Composition.ExportAttribute] 特性将其定义为组合部件(Composabl ...