对最长公共子序列(LCS)等一系列DP问题的研究
LIS问题:
设\(f[i]\)为以\(a[i]\)结尾的最长上升子序列长度,有:
\]
可以用树状数组优化至\(O(nlogn)\)
基于排列的LCS问题(\(a,b\)均为排列,即一个元素不会出现多次):
设\(pos_i\)为\(a_i\)在\(b\)中出现的位置,即\(a_i=b_pos_i\)。
\(a\)的一个子序列\(a_p_1,a_p_2,...,a_p_m\)是\(a,b\)的公共子序列等价于\(pos_p_1<pos_p_2<...<pos_p_m\)
求一个LIS即可。
一般LCS问题:
- 经典解法:
设\(f[i][j]\)表示只考虑\(a\)中前\(i\)个,\(b\)中前\(j\)个的最长公共子序列长度,有: 
\begin{aligned}
& f[i-1][j-1] & a[i]=b[j]\\
& max(f[i-1][j],f[i][j-1]) & a[i]!=b[j]\\
\end{aligned}
\right.\]
十分简单,但是还有一种稍微复杂但是拓展性更高的做法:
设$f[i][j]$表示只考虑$a$中前$i$个,$b$中前$j$个并且$b_j$已经和$a_1,...,a_i$中的某一个匹配的最长公共子序列长度,有:
\begin{aligned}
& f[i-1][j] & a[i]!=b[j]\\
& max(f[i-1][k]+1) & a[i]==b[j],k<j\\
\end{aligned}
\right.\]
为什么说这样拓展性更好?来看这样一道题
题目要求最长上升公共子序列,不能直接用LCS的经典解法了,但是我们仔细思考一下,发现如果我们用上面的转移方程,我们只需要在从\(f[i-1][k]\)转移到\(f[i][j]\)时,只需要保证\(b[k]<b[j]\)即可,所以我们得到新的转移方程:
\begin{aligned}
& f[i-1][j] & a[i]!=b[j]\\
& max(f[i-1][k]+1) & a[i]==b[j],k<j&&b[k]<b[j]\\
\end{aligned}
\right.\]
又因为当\(a[i]==b[j]\)时,\(b[k]<b[j]\)等价于\(b[k]<a[i]\),在转移枚举\(j\)时对所有\(b[k]<a[i]\)的\(f[i-1][k]\)记录一个前缀\(max\)即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 5007
int f[N],a[N],b[N];
int main()
{
	int i,j,n;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
		scanf("%d",&b[i]);
	int maxx=0,ans=0;
	for(i=1;i<=n;i++)
	{
		maxx=0;
		for(j=1;j<=n;j++)
		{
			if(b[j]==a[i])f[j]=max(f[j],maxx+1);
			else if(b[j]<a[i])maxx=max(maxx,f[j]);
			ans=max(ans,f[j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}
当然还有对于一般LCS问题的\(O(nlogn)\)解法(不严格),同样可以拓展至此题。
在排列中,\(a\)中的每一个元素唯一对应\(b\)中的一个元素,但在一般的LCS问题中不是这样,一个元素可以对应多个元素。
怎么办呢?我们把\(a\)中每个元素在\(b\)中对应位置的集合拿出来,比如\(a={3,3,2,4},b={2,3,3,5}\),那么\(a\)中元素\(3\)对应的位置集合就是{2,3},将每个元素对应位置降序排列,再放回原序列中,对得到的新序列做一个LIS,就是最长公共子序列的长度,比如上面那个例子,a中每个元素对应集合为\(\{2,3\},\{2,3\},\{1\},\{\}\),得到的新序列就是\(3,2,3,2,1\),它的最长上升子序列是\(2,3\),即\(a,b\)的最长公共子序列是由\(b_2,b_3\)组成的,这时再套用LIS的\(O(nlogn)\)做法即可,但是这样复杂度不是严格\(O(nlogn)\)的,因为每个\(a\)中的元素最多对应\(n\)个b中的元素,最坏复杂度达到\(O(n^2 log n)\)。
至于这种做法到上面这题的拓展,因为你要保证你在\(a\)中选择的元素在\(b\)中的位置是递增的,同时要保证这些元素的值本身也是递增的,也就是这样:
\]
发现是转移一个二维偏序关系,二维数点即可,复杂度是不严格的\(O(nlog^2 n)\)。
对最长公共子序列(LCS)等一系列DP问题的研究的更多相关文章
- 1006 最长公共子序列Lcs
		
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdks ...
 - 动态规划之最长公共子序列LCS(Longest Common Subsequence)
		
一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...
 - 编程算法 - 最长公共子序列(LCS) 代码(C)
		
最长公共子序列(LCS) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定两个字符串s,t, 求出这两个字符串最长的公共子序列的长度. 字符 ...
 - C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解
		
版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...
 - POJ 1458 Common Subsequence(最长公共子序列LCS)
		
POJ1458 Common Subsequence(最长公共子序列LCS) http://poj.org/problem?id=1458 题意: 给你两个字符串, 要你求出两个字符串的最长公共子序列 ...
 - 51Nod 1006:最长公共子序列Lcs(打印LCS)
		
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...
 - 51nod 1006 最长公共子序列Lcs 【LCS/打印path】
		
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...
 - 题解报告:hdu 1159 Common Subsequence(最长公共子序列LCS)
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 Problem Description 给定序列的子序列是给定的序列,其中有一些元素(可能没有) ...
 - 每日一题-——最长公共子序列(LCS)与最长公共子串
		
最长公共子序列(LCS) 思路: 代码: def LCS(string1,string2): len1 = len(string1) len2 = len(string2) res = [[0 for ...
 - 51nod 1006:最长公共子序列Lcs
		
1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...
 
随机推荐
- 微信小程序子组件样式不起作用的解决办法
			
今天我在编写微信小程序项目时,发现父组件引用子组件过后,子组件的样式不起作用,在上网查了很多解决办法后,成功解决了这一问题. 解决办法: 1.在全局样式文件app.wxss中引入子组件的样式,如 @i ...
 - SQL  -----------     join  (inner join  内连接)
			
SQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段,把两个表中的数据放在一个表中查询 注意: join 连接有多种方式,比如内连接,外连接,交叉连接 可以和where ...
 - SQLServer          ---------   设置主键自增长
			
设置主键自增长的两种方式 1.通过图形化的的操作方法进行设置 新建的时候进行设置 第二种是右击设计对已经建好的表进行设置 设置主键 设置自增长 标识增量标识每次自增加多少 标识种子标识从多少开始自 ...
 - Ubuntu无法进入图形化界面(报错/dev/sda1:clean的解决)
			
进入命令行模式,执行下面的命令: rm -rf /etc/X11/xorg.conf cp /etc/X11/xorg.conf.failsafe /etc/X11/xorg.conf 重启电脑. 上 ...
 - HUT 排序训练赛 F - 水果
			
Problem's Link Mean: 略. analyse: 使用结构体排序. 首先,定义一个结构体,用来存放输入的数据,然后就是输入,注意:这儿有一个小细节,输入数字,然后紧跟着输入字符串,这时 ...
 - 【题解】邻值查找 [CH1301]
			
[题解]邻值查找 [CH1301] 传送门:邻值查找 \([CH1301]\) \([AcWing136]\) [题目描述] 给定一个长度为 \(n\) 的序列 \(A\),\(A\) 中的数各不相同 ...
 - Blend Brush介绍
			
原文:Blend Brush介绍 这篇文章会介绍 Blend怎么设置Brush 全局画刷 1)blend面板的介绍 这5个rectangle分别对应 blend中的 5个设置 1 设置无颜色 2 设置 ...
 - ASP.NET Core部署IIS问题总结
			
部署准备工作 1.服务器开启添加IIS相关功能 1.1. 点击windows搜索到 “启用或关闭windows功能” 1.2 选择添加IIS的部分功能, 如下图所示 2.进入IIS,添加已经发布的 ...
 - Python——Scrapy爬取链家网站所有房源信息
			
用scrapy爬取链家全国以上房源分类的信息: 路径: items.py # -*- coding: utf-8 -*- # Define here the models for your scrap ...
 - 万张PubFig人脸数据实现基于python+OpenCV的人脸特征定位程序(1)
			
在最近刷今日头条以及其他媒体软件时,经常会发现一些AI换脸的视频,于是我想,可不可以自己实现一个可以进行人脸识别的软件程序.我的具体流程是先配合python网络爬虫先进行万张PubFig人脸公共图片的 ...