yzoj1985 最长公共单调上升子序列 题解
题面给两个序列a,b长度分别为n,m求最长公共上升子序列,百度了一下求公共子序列的问题好像叫做LCS,而上升的叫做LCIS。都是dp的例题。
先来说说最长公共子序列,这是一道比较经典的dp题,我们可以很容易写出
1.状态F[i][j]表示a序列匹配到第i个b序列匹配到第j个的最长长度
2.状态转移方程
F[i][j] = max(F[i-1][j] , F[i][j-1]) (a[i] != b[j])
F[i][j] = F[i-1][j-1]+1(a[i] = b[j])
答案就在F[n][m]中
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,f[5010][5010];
char a[5010],b[5010];
int main(){
scanf("%s",a+1);
scanf("%s",b+1);
n=strlen(a+1);
m=strlen(b+1);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
}
}
printf("%d",f[n][m]);
return 0;
}
然后我们再来考虑最长公共上升子序列
1.定义状态:F[x][y]表示a串匹配长度x,b串匹配长度y,且以b[j]结尾的序列长度。
2.状态转移方程:
F[i][j]=F[i][j] = F[i-1][j] (a[i] != b[j])
F[i][j] = max(F[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k])
对于第一个方程我们可以理解为当a[i]!=a[j]时我们用b序列去匹配a序列匹配失败了则a[i]这个数是对这个序列没有贡献的,即考虑不考虑都无所谓
对于第二个方程我们可以理解为当b序列中第j个数匹配了,我们可以选择前面所有的状态进行转移,但是保证 b[j] > b[k]
#include<bits/stdc++.h>
using namespace std;
int n,m,ans,a[3010],b[3010],f[3010][3010];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
f[i][j]=f[i-1][j];
if(a[i]==b[j]){
int maxn=0;
for(int k=1;k<=j-1;++k){
if(b[j]>b[k]) maxn=max(maxn,f[i-1][k]);
}
f[i][j]=maxn+1;
}
}
}
for(int i=1;i<=m;++i) ans=max(ans,f[n][i]);
printf("%d",ans);
return 0;
}
但是这样的做法在最坏情况下可能到达O(n^3),我们可以考虑优化,我们可以发现在第三重循环找最大值时是否可以进行一定优化?我们可以发现当有一个序列a[i]=b[j]时看第二个转移方程b[j] > b[k]也就是说a[i]>b[k],我们可以利用一个最大值maxn来存下每次的最大值,即当a[i]>b[j]时更新它,当a[i]=b[j]时f[i][j]=maxn+1;
#include<bits/stdc++.h>
using namespace std;
int n,m,ans,a[3010],b[3010],f[3010][3010];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
for(int i=1;i<=n;++i){
int maxn=0;
for(int j=1;j<=m;++j){
f[i][j]=f[i-1][j];
if(a[i]>b[j]) maxn=max(maxn,f[i-1][j]);
if(a[i]==b[j]) f[i][j]=maxn+1;
}
}
for(int i=1;i<=m;++i) ans=max(ans,f[n][i]);
printf("%d",ans);
return 0;
}
我们依然可以发现f[i][j]转移只用到了f[i][j-1]的数,我们可以再进行优化!利用滚动数组优化我们的空间。
#include<bits/stdc++.h>
using namespace std;
int n,m,ans,a[3010],b[3010],f[3010];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
for(int i=1;i<=n;++i){
int maxn=0;
for(int j=1;j<=m;++j){
if(a[i]>b[j]) maxn=max(maxn,f[j]);
if(a[i]==b[j]) f[j]=maxn+1;
}
}
for(int i=1;i<=m;++i) ans=max(ans,f[i]);
printf("%d",ans);
return 0;
}
完结撒花!!
yzoj1985 最长公共单调上升子序列 题解的更多相关文章
- 【JZOJ4889】【NOIP2016提高A组集训第14场11.12】最长公共回文子序列
题目描述 YJC最近在学习字符串的有关知识.今天,他遇到了这么一个概念:最长公共回文子序列.一个序列S,如果S是回文的且分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...
- 最长公共子串和子序列的Python实现,带图示。
使用矩阵来记录两个子串之间各个字符之间的对应关系. 最长子串:矩阵中数字最大的就是最长子串的长度.若对应位置字符相同,则c[i][j] = c[i-1][j-1] + 1 def longSubStr ...
- 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串
LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...
- SCOJ 4493: DNA 最长公共子串 后缀自动机
4493: DNA 题目连接: http://acm.scu.edu.cn/soj/problem.action?id=4493 Description Deoxyribonucleic acid ( ...
- 【LCS,LIS】最长公共子序列、单调递增最长子序列
单调递增最长子序列 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4 输入 ...
- C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解
版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...
- [C++] 动态规划之矩阵连乘、最长公共子序列、最大子段和、最长单调递增子序列、0-1背包
一.动态规划的基本思想 动态规划算法通常用于求解具有某种最优性质的问题.在这类问题中,可能会有许多可行解.每一个解都对应于一个值,我们希望找到具有最优值的解. 将待求解问题分解成若干个子问题,先求解子 ...
- 算法复习周------“动态规划之‘最长公共子序列’”&&《计蒜课》---最长公共子串题解
问题描述: 这个问题其实很容易理解.就是给你两个序列X={x1,x2,x3......xm} Y={y1,y2,y3......ym},要求找出X和Y的一个最长的公共子序列. 例:Xi={A, B, ...
- 题解报告:hdu 1159 Common Subsequence(最长公共子序列LCS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 Problem Description 给定序列的子序列是给定的序列,其中有一些元素(可能没有) ...
随机推荐
- 为什么你要用 Spring?
前言 现在Spring几乎成为了Java在企业级复杂应用开发的代名词,得益于Spring简单的设计哲学和其完善的生态圈,确实为廉颇老矣,尚能饭否的 Java 带来了“春天”,有很多同学刚接触Jav ...
- 爬虫获取搜狐汽车的配置信息 和swf动态图表的销量数据-------详细教学
前情提要:需要爬取搜狐汽车的所有配置信息,具体配置对应的参数. 以及在动态图表上的历史销量. 比如: 一汽奥迪旗下Q5L 的<40 TFSI 荣享进取型 国VI >的历史销量和该配置的参数 ...
- byte数组和正数BigInteger之间的相互转换
旧代码 public static void main(String[] args) { SecureRandom random = new SecureRandom(); byte[] key = ...
- .NETCore C# 中级篇2-4 一文带你完全弄懂正则表达式
.NETCoreCSharp 中级篇2-4 本节内容为正则表达式的使用 简介 有的时候,你是否有过这种需求:判断一个Ip地址.邮箱.密码规则是否合法.如果让你使用if一类的传统方法进行处理,你肯定会被 ...
- vscode中配置git
vscode中配置git vscode 报错 未找到Git.请安装Git,或在"git.path" 设置中配置 第一步安装git git安装方法自行解决,提供git下载连接! gi ...
- Python项目中的单元测试
引入 单元测试负责对最小的软件设计单元(模块)进行验证,unittest是Python自带的单元测试框架. 单元测试与功能测试都是日常开发中必不可少的部分,本文演示了Python中unittest单元 ...
- 当我们尝试用JavaScipt测网速
npm包地址 https://www.npmjs.com/package/network-speed-test Github地址 https://github.com/penghuwan/networ ...
- Elasticsearch由浅入深(一)
什么是Elasticsearch 什么是搜索 百度:我们比如说想找寻任何的信息的时候,就会上百度去搜索一下,比如说找一部自己喜欢的电影,或者说找一本喜欢的书,或者找一条感兴趣的新闻(提到搜索的第一印象 ...
- springBoot入门教程(图文+源码+sql)
springBoot入门 1 springBoot 1.1 SpringBoot简介 Spring Boot让我们的Spring应用变的更轻量化.比如:你可以仅仅依靠一个Java类来运行一个Spr ...
- SparkSQL Adaptive Execution
转自 https://mp.weixin.qq.com/s/Oq9L3Cmc-8G9oL8dvZ5OHQ 1 背景 本文介绍的 Adaptive Execution 将可以根据执行过程中的中间数据优化 ...