最长公共子序列问题LCS
最长公共子序列问题
在这里介绍一种在动态规划中类似于板子题的类型 : 最长公共子序列问题。(Link)
首先来看题面:给出1-n的两个排列P1和P2,求它们的最长公共子序列。
我们看到题之后的第一个想法肯定就是一个O(n^2) 的DP,但是看到数据:
对于\(100\)%的数据,\(n≤100000\)
那么我们知道肯定是过不了的了,那么我们考虑一个\(O(nlogn)\)的DP方法。
首先构造一个\(K[MAXN]\)数组,这个数组的用处是用来记录一个数字在字串S1中的位置。因为S1和S2都是由1到n的排列,那么这个位置肯定是唯一的。
然后我们结合样例分析。
\(S1\) : {\(3, 2, 1, 4, 5\)} ; \(S2\) : {\(1, 2, 3, 4, 5\)} ; 当然答案很显然是\(3\)。也就是{\(3, 4, 5\)}或者{\(2, 4, 5\)}
当前的\(K\)对于每一个\(S2\)中的数的数组就是:{\(3, 2, 1, 4, 5\)}。那么我们考虑这个一个事情:如果\(S2\)序列的每一个元素如果在\(S1\)序列中的位置是递增的,那么也就说明\(S1\)中的数在\(S2\)中都偏后。那么我们就可以将问题转变为求\(K\)数组中的最长上升子序列。
那么问题来了,最长上升子序列怎么求呢?
当然考虑\(DP\),那么我们可以显而易见地得出一个\(O(n^2)\)的算法:设\(F[i][j]\)为第一个序列中前i个元素和第j和序列中前j个元素中的最长上升子序列的长度是多少。那我们对于每一个枚举到的\(i\),再枚举在\(i\)之前的所有元素\(j\),如果\(Data[j] < Data[i]\)并且\(Dp[j] + 1 > Dp[i]\),那么我们就让\(Dp[i]\)继承\(Dp[j]\)然后再加上\(1\)。
\[Dp[i] = max_{j = 1}^{j <= i}(Dp[i], Dp[j] + 1)\]
void LIS(){
for(int i = 1; i <= N; i ++)
for(int j = 1; j <= i; j ++)
if(Data[j] < Data[i])
Dp[i] = max(Dp[i], Dp[j] + 1) ;
}
但是我们会发现这种做法并不可行因为它的时间复杂度仍然是\(O(n^2)\),所以我们考虑使用一个\(F[i]\)表示长度为\(i\)的最长上升子序列的最后一位的最小值是多少。记这个玩意干什么呢?你想,你现在有一个最长上升子序列的长度为\(i\),最后一位的值是\(T\),那么当你选择下一位\(i + 1\)的时候,你的选择范围只有\([T, max_{i = 1}^{i <= N}Data[i]]\),那么你的T越小,可以选择的范围就越大。运用这个贪心的思想,我们可以发现在第二次枚举的时候,我们就可以二分查找了。
//LIS (Longest Rising Subsequence)
int F[MAXN] ;
void LIS(){
for(int i = 1; i <= N; i ++){
Data[i] = Read() ;
F[i] = Inf ;
}
F[1] = Data[1] ; int Tot = 1 ;
for(int i = 2; i <= N; i ++){
int L = 0, R = Tot ;
if(Data[i] > F[Tot]) F[++ Len] = Data[i] ;
else{
while(L < R){
// 因为F[j]的值一定是递增的,所以可以二分查找第一个小于等于Data[i]的点
if(F[Mid] > Data[i])
R = Mid ;
else L = Mid + 1 ;
}
F[L] = min(F[L], Data[i]) ;
}
}
// Ans : Tot ;
}
那么我们也就得出了最长上升子序列的问题的解。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#define For1(i, A, B) for(register int i = (A), i##_end_ = (B); i <= i##_end_; ++ i)
#define For2(i, A, B) for(register int i = (A), i##_end_ = (B); i >= i##_end_; -- i)
#define MEM(Now, K) memset(Now, K, sizeof(Now))
#define CPY(Now, K) memcpy(Now, K, sizeof(Now))
#define Debug(Now) (cerr << Now << endl)
#define Min(A, B) (A < B ? A : B)
#define Max(A, B) (A < B ? B : A)
#define Mid ((L + R) >> 1)
#define SCPY(A, B) strcpy(A, B)
#define Inf 0x7fffffff
#define RE register
#define IL inline
#define MAXN 100010
#define MAXM 100010
#define _X first
#define _Y second
using namespace std ;
typedef unsigned long long ULL ;
typedef pair<long long, int> PLI;
typedef pair<int, int> PII;
typedef unsigned int UINT;
typedef long double LDB;
typedef long long LL ;
typedef double DB ;
IL int Read(){
int X = 0, F = 1 ; char ch = getchar() ;
while(ch < '0' || ch > '9'){ if(ch == '-') F = - 1 ; ch = getchar() ; }
while(ch <= '9' && ch >= '0') X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;
return X * F ;
}
IL double DBRead(){
double X = 0, Y = 1.0 ; int W = 0 ; char ch = 0 ;
while(! isdigit(ch)) { W |= ch == '-' ; ch = getchar() ; }
while(isdigit(ch)) X = X * 10 + (ch ^ 48), ch = getchar() ;
ch = getchar();
while(isdigit(ch)) X += (Y /= 10) * (ch ^ 48), ch = getchar() ;
return W ? - X : X ;
}
IL void Print(int X){
if(X < 0) putchar('-'), X = - X ;
if(X > 9) Print(X / 10) ; putchar(X % 10 + '0') ;
}
int N, S1[MAXN], S2[MAXN], F[MAXN], K[MAXN] ;
int LCS(){ // Return the lenth of LCS
N = Read() ;
for(int i = 1; i <= N; i ++){
S1[i] = Read() ;
K[S1[i]] = i ;
}
for(int i = 1; i <= N; i ++){
S2[i] = Read() ;
F[i] = Inf ;
}
int Tot = 0 ; F[0] = 0 ;
for(int i = 1; i <= N; i ++){
int L = 0, R = Tot ;
if(K[S2[i]] > F[Tot]) F[++ Tot] = K[S2[i]] ;
else{
while(L < R){
if(F[Mid] > K[S2[i]])
R = Mid ;
else L = Mid + 1 ;
}
F[L] = min(F[L], K[S2[i]]) ;
}
}
return Tot ;
}
int main() {
Print(LCS()) ;
return 0 ;
}
最长公共子序列问题LCS的更多相关文章
- 最长公共子序列问题 (LCS)
给定两个字符串S和T.求出这两个字符串最长的公共子序列的长度. 输入: n=4 m=4 s="abcd" t="becd" 输出: 3("bcd&qu ...
- 动态规划法(十)最长公共子序列(LCS)问题
问题介绍 给定一个序列\(X=<x_1,x_2,....,x_m>\),另一个序列\(Z=<z_1,z_2,....,z_k>\)满足如下条件时称为X的子序列:存在一个严格 ...
- 动态规划经典——最长公共子序列问题 (LCS)和最长公共子串问题
一.最长公共子序列问题(LCS问题) 给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子序列,并返回其长度.例如: A = "HelloWorld" B = & ...
- 【Luogu P1439】最长公共子序列(LCS)
Luogu P1439 令f[i][j]表示a的前i个元素与b的前j个元素的最长公共子序列 可以得到状态转移方程: if (a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1; d ...
- 最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)
最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字 ...
- 删除部分字符使其变成回文串问题——最长公共子序列(LCS)问题
先要搞明白:最长公共子串和最长公共子序列的区别. 最长公共子串(Longest Common Substirng):连续 最长公共子序列(Longest Common Subsequence,L ...
- 最长公共子序列(LCS)和最长递增子序列(LIS)的求解
一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...
- 算法导论-动态规划(最长公共子序列问题LCS)-C++实现
首先定义一个给定序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果,其形式化定义如下:给定一个序列X = <x1,x2 ,..., xm>,另一个序列Z =<z1,z2 ...
- 最长公共子序列(LCS问题)
先简单介绍下什么是最长公共子序列问题,其实问题很直白,假设两个序列X,Y,X的值是ACBDDCB,Y的值是BBDC,那么XY的最长公共子序列就是BDC.这里解决的问题就是需要一种算法可以快速的计算出这 ...
- nyoj 36 最长公共子序列【LCS模板】
最长公共子序列 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列.tip:最长公共子序列也称作最 ...
随机推荐
- System.arraycopy的测试
ArrayList的源码中数组的拷贝用到该方法: public static void arraycopy(Object src, --源数组 int srcPos, --源数组要复制的起始位置 Ob ...
- Open Live Writer 安装和博客账号配置
打开Open Live Writer就像您的博客的Word一样.打开Live Writer是一个功能强大,轻量级的博客编辑器,允许您创建博客文章,添加照片和视频,然后发布到您的网站. Open Liv ...
- Java温故而知新(10)类的加载机制
类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性 ...
- Golang 的 TOML库
TOML 的全称是 Tom's Obvious, Minimal Language,因为它的作者是 GitHub 联合创始人 Tom Preston-Werner. TOML 的目标是成为一个极简的配 ...
- VC++ IPv6的支持
最近根据项目需要,要在产品中添加对IpV6的支持,因此研究了一下IPV6的相关内容,Ipv6 与原来最直观的改变就是地址结构的改变,IP地址由原来的32位扩展为128,这样原来的地址结构肯定就不够用了 ...
- 10.31NOIP模拟赛解题报告
心路历程 预计得分:\(100 +100 +80\) 实际得分:\(30 + 100 + 80\) 天天挂分..感觉我noip要凉.. T1不难,但是太坑了 T2不难 T3不难,但是在小机房考试脑子都 ...
- openlayers跨域设置后出现http status 500错误
最近需要弄一下地理信息系统,用到openlayers和geoserver.在解决跨域的时候出现如下问题.求解决方案啊. 问题如下: 附:已经安装了python27,环境变量path中也添加了:c:\P ...
- java jdk切换出现的问题 jdk切换失败(转)
1.问题:同时装两个版本的jdk时出现的问题(本次是1.7和1.8的版本),因为eclipse要求1.8版本的,但是我的Windows默认版本是1.7,导致无法启动eclipse 2.因为做开发的时候 ...
- 如何在 Linux 虚拟机上扩展根文件系统
问题描述 通过 Azure 平台部署的 Linux 虚拟机默认的根文件系统容量有限,需要进行扩展. 问题分析 由于 Azure 平台部署的 Linux 虚拟机默认根文件系统容量比较小,客户在使用过程中 ...
- pt-query-digest(percona toolkit)小解
pt-query-digest可以通过logs, processlist, 和tcpdump来分析MySQL的查询相关信息,基本语法如下: pt-query-digest [OPTIONS] [FIL ...