1. 题目描述

给定两个数列\(A, B\),如果他们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列。求\(A\)和\(B\)的最长公共上升子序列。

输入格式

第一行包含一个整数\(N\),表示\(A\)和\(B\)的长度。

第二行包含\(N\)个整数,表示数列\(A\)。

第三行包含\(N\)个整数,表示数列\(B\)。

输出格式

输出一个整数,表示最长公共上升子序列的长度。

数据范围

\(1 ≤ N≤ 3000\),序列中的数字均不超过\(2^{31} - 1\).

输入样例

4
2 2 1 3
2 1 2 3

输出样例

2

2. 朴素解法\(O(n^3)\)

朴素解法将最长公共子序列和最长上升子序列模型相结合。

用\(f[i][j]\)表示第一个序列的前\(i\)个数,和第二个序列的前\(j\)个数,且最后一个数为\(b[j]\)的最长公共上升子序列的长度。

则可以根据\(a[i]\)是否等于\(b[j]\)进行分类讨论。

\[f[i][j]=\left\{
\begin{array}{rcl}
f[i - 1][j] & & {a[i] != a[j]}\\
max_{k < j且b[k] < b[j]}(f[i][j], f[i- 1][k]) & & {a[i] == b[j] }\\

\end{array} \right.
\]

#include <iostream>
#include <algorithm> using namespace std;
const int N = 3010;
int a[N], b[N];
int n;
int f[N][N]; int main()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> b[i]; for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= n; j ++)
{
f[i][j] = f[i - 1][j];
if(a[i] == b[j])
{
f[i][j] = max(f[i][j], 1);
for(int k = 1; k < j; k ++)
if(b[k] < b[j]) f[i][j] = max(f[i][j], f[i - 1][k] + 1);
}
}
}
int res = 0;
for(int i = 1;i <= n; i ++) res = max(res, f[n][i]);
cout << res << endl;
return 0;
}

3. 代码优化\(O(n^2)\)

上述朴素做法的时间复杂度为\(O(n^3)\)。那么我们如何优化呢?

  • 观察代码的最内层循环部分

     if(a[i] == b[j])
    {
    f[i][j] = max(f[i][j], 1);
    for(int k = 1; k < j; k ++)
    if(b[k] < b[j]) f[i][j] = max(f[i][j], f[i - 1][k] + 1);
    }

    由于执行最内层循环的时候a[i] == b[j]。所以最内层条件可以变为b[k] < a[i]

  • 再来考虑整个循环

    for(int i = 1; i <= n; i ++)
    {
    for(int j = 1; j <= n; j ++)
    {
    f[i][j] = f[i - 1][j];
    if(a[i] == b[j])
    {
    f[i][j] = max(f[i][j], 1);
    for(int k = 1; k < j; k ++)
    if(b[k] < a[i]) f[i][j] = max(f[i][j], f[i - 1][k] + 1);
    }
    }
    }

    我们实际上就是在求:当第一个循环走到i,第二个循环走到j 且满足" a[i] > b[k]k < j "时f[i - 1][j]的最大值。

    也就是说当我们访问到第j层循环的时候,需要前j-1层的数据。因此,可以在j的循环中迭代求解。

    代码如下

    for(int i = 1; i <= n; i ++)
    {
    int maxv = 1;
    for(int j = 1; j <= n; j ++)
    {
    f[i][j] = f[i - 1][j];
    if(a[i] == b[j]) f[i][j] = max(f[i][j],maxv);
    if(b[j] < a[i]) maxv = max(maxv, f[i - 1][j] + 1); // maxv的更新一定要在f[i][j]的更新之后。
    }
    }

4. 总结

  • 本题是最长公共子序列模型和最长上升子序列模型的结合版, 我们可以根据最长上升子序列和最长公共子序列的状态表示方法得到启发,构建状态表示方法和状态转移方程。
  • 朴素解法的时间复杂度较高,但是我们可以根据代码进行优化,将时间复杂度由\(O(n^3)\)降到\(O(n^2)\)。

动态规划-最长公共上升子序列-n^2解法的更多相关文章

  1. 动态规划——最长公共上升子序列LCIS

    问题 给定两个序列A和B,序列的子序列是指按照索引逐渐增加的顺序,从原序列中取出若干个数形成的一个子集,若子序列的数值大小是逐渐递增的则为上升子序列,若A和B取出的两个子序列A1和B1是相同的,则A1 ...

  2. [ACM_动态规划] UVA 12511 Virus [最长公共递增子序列 LCIS 动态规划]

      Virus  We have a log file, which is a sequence of recorded events. Naturally, the timestamps are s ...

  3. codevs 2185 最长公共上升子序列

    题目链接: codevs 2185 最长公共上升子序列codevs 1408 最长公共子序列 题目描述 Description熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升 ...

  4. HDOJ 1423 Greatest Common Increasing Subsequence 【DP】【最长公共上升子序列】

    HDOJ 1423 Greatest Common Increasing Subsequence [DP][最长公共上升子序列] Time Limit: 2000/1000 MS (Java/Othe ...

  5. HDU 4512 最长公共上升子序列

    各种序列复习: (1)最长上升子序列. 1.这个问题用动态规划就很好解决了,设dp[i]是以第i个数字结尾的上升子序列的最长长度.那么方程可以是dp[i]=max(dp[j]+1).(j<i). ...

  6. LCIS 最长公共上升子序列问题DP算法及优化

    一. 知识简介 学习 LCIS 的预备知识: 动态规划基本思想, LCS, LIS 经典问题:给出有 n 个元素的数组 a[] , m 个元素的数组 b[] ,求出它们的最长上升公共子序列的长度. 例 ...

  7. hdu 1423 最长公共递增子序列 LCIS

    最长公共上升子序列(LCIS)的O(n^2)算法 预备知识:动态规划的基本思想,LCS,LIS. 问题:字符串a,字符串b,求a和b的LCIS(最长公共上升子序列). 首先我们可以看到,这个问题具有相 ...

  8. 最长公共上升子序列(codevs 2185)

    题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们要研究最长公共上升子序列了. 小沐沐说,对 ...

  9. 最长公共上升子序列(LCIS)

    最长公共上升子序列慕名而知是两个字符串a,b的最长公共递增序列,不一定非得是连续的.刚开始看到的时候想的是先用求最长公共子序列,然后再从其中找到最长递增子序列,可是仔细想一想觉得这样有点不妥,然后从网 ...

随机推荐

  1. CF1471-B. Strange List

    CF1471-B. Strange List 题意: 给定一个由\(n\)个数字组成的数组以及一个\(x\).现在从前往后遍历数组,若当前遍历的数字\(a[i]\)可以被\(x\)整除,那么就在数组的 ...

  2. Java RMI 实现一个简单的GFS(谷歌文件系统)——介绍篇

    本系列主要是使用Java RMI实现一个简单的GFS(谷歌文件系统,google file system),首先整体简单介绍下该项目. [为了更好的阅读以及查看其他篇章,请查看原文:https://w ...

  3. bzoj4695 最假女选手(势能线段树/吉司机线段树)题解

    题意: 已知\(n\)个数字,进行以下操作: \(1.\)给一个区间\([L,R]\) 加上一个数\(x\) \(2.\)把一个区间\([L,R]\) 里小于\(x\) 的数变成\(x\) \(3.\ ...

  4. POJ 3415 Common Substrings(后缀数组 + 单调栈)题解

    题意: 给两个串\(A.B\),问你长度\(>=k\)的有几对公共子串 思路: 先想一个朴素算法: 把\(B\)接在\(A\)后面,然后去跑后缀数组,得到\(height\)数组,那么直接\(r ...

  5. springboot使用RestTemplate+httpclient连接池发送http消息

    简介 RestTemplate是spring支持的一个请求http rest服务的模板对象,性质上有点像jdbcTemplate RestTemplate底层还是使用的httpclient(org.a ...

  6. u-boot 移植 --->4、Tiny210核心板的DDR初始化下详解

    RAM的原理简单学习 DDR是RAM的一种,RAM常见的类型有SRAM,SDRAM,DDR他们的共同特点是,随机存储意味着读写速度快,掉电后数据丢失,所以常用来存储程序中的变量. SRAM 静态随机存 ...

  7. Linux Schedule Cron All In One

    Linux Schedule Cron All In One 定时任务 / 定时器 GitHub Actions Scheduled events Cron syntax has five field ...

  8. three.js all in one

    three.js all in one https://www.npmjs.com/package/three # yarn add three # OR $ npm i three https:// ...

  9. TypeScript 面试题汇总(2020 版)

    TypeScript 面试题汇总(2020 版) TypeScript 3.9 https://www.typescriptlang.org/zh/ TypeScript 4.0 RC https:/ ...

  10. Node.js Learning Paths

    Node.js Learning Paths Node.js in Action Node.js Expert situations / scenario Restful API OAuth 2.0 ...