题面给两个序列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. IO流与NIO流

    JAVA IO流最详解   (转自CSDN) IO流上:概述.字符流.缓冲区(java基础)   一.IO流概述 概述: IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间的数 ...

  2. leetcode并发题目解题报告JAVA版

    一.Print in Order Suppose we have a class: public class Foo { public void first() { print("first ...

  3. 完全零基础在Linux中安装 JDK

    完全零基础在Linux中安装 JDK 总体思路:先确定没有Java程序了 — 然后创建相应路径文件夹 — 下载JDK — 解压到当前路径 — 自定义文件名称 — 配置环境变量 — 检查是否安装成功 第 ...

  4. 简易数据分析 09 | Web Scraper 自动控制抓取数量 & Web Scraper 父子选择器

    这是简易数据分析系列的第 9 篇文章. 今天我们说说 Web Scraper 的一些小功能:自动控制 Web Scraper 抓取数量和 Web Scraper 的父子选择器. 如何只抓取前 100 ...

  5. ArrayList 的使用方法【摘要】

    ArrayList 的使用方法 1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: (1)动态的增加和减少元素 ...

  6. 10.Go-goroutine,waitgroup,互斥锁和channel

    10.1.goroutine goroutine的使用 //Learn_Go/main.go package main import ( "fmt" "time" ...

  7. 转载 | CSS实现单行、多行文本溢出显示省略号(…)

    本文引自:https://www.cnblogs.com/wyaocn/p/5830364.html 首先,要知道css的三条属性. overflow:hidden; //超出的文本隐藏 text-o ...

  8. Mermaid

    graph TD; A-->B; A-->C; B-->D; C-->D;

  9. android——卡片式布局

    一.CardView <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk ...

  10. Win服务程序编写以及安装一般步骤

    Win服务程序编写以及安装一般步骤 Windows服务的优点有:1. 能够自动运行.2. 不要求用户交互.3. 在后台运行.本文将介绍常见服务程序编写的一般步骤以及注意事项. 设计服务程序实例: 创建 ...