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. 男孩周末班-k8s-思维导图

  2. LINUX - 寄存器和堆栈

    堆栈模型: 函数调用: EBP:ESP EBP当前调用函数的栈底: ESP当前调用函数的栈顶: ---------------------------------------------------- ...

  3. _.shuffle、_.debounce中下划线对象的理解

    Vue 官方教程中有_.shuffle._.debounce,不明白"_"是怎么来的,有什么意义? Lodash 和 Underscorejs 都有相关解释

  4. 【算法】KMP算法

    简介 KMP算法由 Knuth-Morris-Pratt 三位科学家提出,可用于在一个 文本串 中寻找某 模式串 存在的位置. 本算法可以有效降低在一个 文本串 中寻找某 模式串 过程的时间复杂度.( ...

  5. website text select notes menu

    website text select notes menu website 文字选择笔记菜单(下划线, 标记, 复制, 分享) 下划线, 标记 https://time.geekbang.org/ ...

  6. convert image to base64 in javascript

    convert image to base64 in javascript "use strict"; /** * * @author xgqfrms * @license MIT ...

  7. Flatten Arrays & flat() & flatMap()

    Flatten Arrays & flat() & flatMap() https://alligator.io/js/flat-flatmap/ "use strict&q ...

  8. Github & DMCA Takedown & git remove history

    Github & DMCA Takedown & git remove history Github & DMCA Takedown Policy Removing files ...

  9. GMV (Gross Merchandise Volume)

    GMV (Gross Merchandise Volume) 商品总销量 https://www.zhihu.com/question/20146641 GMV=1销售额+2取消订单金额+3拒收订单金 ...

  10. c++ 使用进程id获取打开的网络端口

    #pragma warning( disable : 4996) #include <winsock2.h> #include <ws2tcpip.h> #include &l ...