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. Python_微信支付(云开发)

    一.创建云开发小程序 1.初始化云开发环境 //app.js App({ onLaunch: function () { wx.cloud.init({ //初始化云开发环境 env: 'wxypay ...

  2. OpenStack Train版-2.安装keystone身份认证服务

    安装 keystone 认证 mysql -uroot create database keystone; grant all privileges on keystone.* to 'keyston ...

  3. VS制作可自动覆盖旧版本的安装包

    1.设置属性 DetectNewerInstalledVersion=TrueInstallAllUsers = TrueRemovePreviousVersion = True 2.增加软件版本号, ...

  4. 牛客网多校第4场 J Hash Function 【思维+并查集建边】

    题目链接:戳这里 学习博客:戳这里 题意: 有n个空位,给一个数x,如果x%n位数空的,就把x放上去,如果不是空的,就看(x+1)%n是不是空的. 现在给一个已经放过数的状态,求放数字的顺序.(要求字 ...

  5. 三、mysql主从复制

    1 MySQL 主从复制 1.1 主从复制的含义 在 MySQL 多服务器的架构中,至少要有一个主节点(master),跟主节点相对的,我们把它叫做从节点(slave). 主从复制,就是把主节点的数据 ...

  6. IIS6.0(CVE-2017-7269) 缓冲器溢出

    漏洞描述开启WebDAV服务对IIS 6.0存在缓冲区溢出漏洞都可以导致远程代码执行,所以对于目前的IIS 6.0用户而言,可用的变通方案就是关闭WebDAV服务. 漏洞编号CVE-2017-7269 ...

  7. window.ShadyCSS

    window.ShadyCSS Web Components # install $ yarn add @webcomponents/shadycss@1.7.1 # OR $ npm i @webc ...

  8. CSS flex waterfall layout

    CSS flex waterfall layout https://github.com/YoneChen/waterfall-flexbox https://css-tricks.com/snipp ...

  9. nasm astrcpy_s函数 x86

    xxx.asm %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export ast ...

  10. Flutter: SearchDelegate 委托showSearch定义搜索页面的内容

    API class _MyHomeState extends State<MyHome> { List<String> _list = List.generate(100, ( ...