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. SpringSecurity认证流程

    SpringSecurity配置 SecurityConfig.java @Override protected void configure(HttpSecurity http) throws Ex ...

  2. 牛客网-n的约数【dfs】

    题目描述:戳这里 解题思路:这题思路好想,n最多也就是20个不同的素数相乘,把所有可能的素数找到,然后枚举素数个数就行了. n = p1^q1 + p2^q2 + p3 ^q3 + ... + pi ...

  3. hdu-1159 1087 1257(dp)

    本文就最长公共子序列,最长连续递增子序列的长度,最大连续递增子序列的值进行对比. hdu-1159: Common Subsequence Time Limit: 2000/1000 MS (Java ...

  4. Tomcat基本原理

    思考 :怎样让Tomcat具备Web服务的功能呢? 在服务端用HTTP来监听,协议不好写,不妨用Java封装好的Socket作为监听. class MyTomcat{ ServerSocket ser ...

  5. js create Array ways All In One

    js create Array ways All In One ES6 const arr = [...document.querySelectorAll(`[data-dom="^div& ...

  6. element-ui select get selected option object

    element-ui select get selected option object value-key="value" === String :value="{va ...

  7. 如何使用 VuePress 搭建一个 element-ui 风格的文档网站

    如何使用 VuePress 搭建一个 element-ui 风格的文档网站 { "devDependencies": { "vuepress": "1 ...

  8. Graphviz - Graph Visualization Software 开源可视化绘图工具(visio 类)

    http://www.graphviz.org/Download_windows.php Welcome to Graphviz Available translations:  Romanian,  ...

  9. js & anti craw & crawler spam

    js & anti craw & crawler spam demo & X-Sign , function(t, e, n) { "use strict" ...

  10. css animation & animation-fill-mode

    css animation & animation-fill-mode css animation effect https://developer.mozilla.org/en-US/doc ...