题面给两个序列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 最长公共单调上升子序列 题解的更多相关文章

  1. 【JZOJ4889】【NOIP2016提高A组集训第14场11.12】最长公共回文子序列

    题目描述 YJC最近在学习字符串的有关知识.今天,他遇到了这么一个概念:最长公共回文子序列.一个序列S,如果S是回文的且分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...

  2. 最长公共子串和子序列的Python实现,带图示。

    使用矩阵来记录两个子串之间各个字符之间的对应关系. 最长子串:矩阵中数字最大的就是最长子串的长度.若对应位置字符相同,则c[i][j] = c[i-1][j-1] + 1 def longSubStr ...

  3. 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串

    LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...

  4. SCOJ 4493: DNA 最长公共子串 后缀自动机

    4493: DNA 题目连接: http://acm.scu.edu.cn/soj/problem.action?id=4493 Description Deoxyribonucleic acid ( ...

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

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

  6. C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解

    版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...

  7. [C++] 动态规划之矩阵连乘、最长公共子序列、最大子段和、最长单调递增子序列、0-1背包

    一.动态规划的基本思想 动态规划算法通常用于求解具有某种最优性质的问题.在这类问题中,可能会有许多可行解.每一个解都对应于一个值,我们希望找到具有最优值的解. 将待求解问题分解成若干个子问题,先求解子 ...

  8. 算法复习周------“动态规划之‘最长公共子序列’”&&《计蒜课》---最长公共子串题解

    问题描述: 这个问题其实很容易理解.就是给你两个序列X={x1,x2,x3......xm} Y={y1,y2,y3......ym},要求找出X和Y的一个最长的公共子序列. 例:Xi={A, B, ...

  9. 题解报告:hdu 1159 Common Subsequence(最长公共子序列LCS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 Problem Description 给定序列的子序列是给定的序列,其中有一些元素(可能没有) ...

随机推荐

  1. 为什么你要用 Spring?

    ​ 前言 现在Spring几乎成为了Java在企业级复杂应用开发的代名词,得益于Spring简单的设计哲学和其完善的生态圈,确实为廉颇老矣,尚能饭否的 Java 带来了“春天”,有很多同学刚接触Jav ...

  2. 爬虫获取搜狐汽车的配置信息 和swf动态图表的销量数据-------详细教学

    前情提要:需要爬取搜狐汽车的所有配置信息,具体配置对应的参数. 以及在动态图表上的历史销量. 比如: 一汽奥迪旗下Q5L 的<40 TFSI 荣享进取型 国VI >的历史销量和该配置的参数 ...

  3. byte数组和正数BigInteger之间的相互转换

    旧代码 public static void main(String[] args) { SecureRandom random = new SecureRandom(); byte[] key = ...

  4. .NETCore C# 中级篇2-4 一文带你完全弄懂正则表达式

    .NETCoreCSharp 中级篇2-4 本节内容为正则表达式的使用 简介 有的时候,你是否有过这种需求:判断一个Ip地址.邮箱.密码规则是否合法.如果让你使用if一类的传统方法进行处理,你肯定会被 ...

  5. vscode中配置git

    vscode中配置git vscode 报错 未找到Git.请安装Git,或在"git.path" 设置中配置 第一步安装git git安装方法自行解决,提供git下载连接! gi ...

  6. Python项目中的单元测试

    引入 单元测试负责对最小的软件设计单元(模块)进行验证,unittest是Python自带的单元测试框架. 单元测试与功能测试都是日常开发中必不可少的部分,本文演示了Python中unittest单元 ...

  7. 当我们尝试用JavaScipt测网速

    npm包地址 https://www.npmjs.com/package/network-speed-test Github地址 https://github.com/penghuwan/networ ...

  8. Elasticsearch由浅入深(一)

    什么是Elasticsearch 什么是搜索 百度:我们比如说想找寻任何的信息的时候,就会上百度去搜索一下,比如说找一部自己喜欢的电影,或者说找一本喜欢的书,或者找一条感兴趣的新闻(提到搜索的第一印象 ...

  9. springBoot入门教程(图文+源码+sql)

    springBoot入门 1   springBoot 1.1 SpringBoot简介 Spring Boot让我们的Spring应用变的更轻量化.比如:你可以仅仅依靠一个Java类来运行一个Spr ...

  10. SparkSQL Adaptive Execution

    转自 https://mp.weixin.qq.com/s/Oq9L3Cmc-8G9oL8dvZ5OHQ 1 背景 本文介绍的 Adaptive Execution 将可以根据执行过程中的中间数据优化 ...