动态规划-LCS、LIS 川长思鸟来 2023-03-02 10:22 5阅读 0赞 ### 文章目录 ### * L C S LCS LCS * L I S LIS LIS # L C S LCS LCS # -------------------- **LCS(Longest Common Subsequence)最长公共子序列**。给定两个序列a和b,当另一序列c即是a的子序列又是b的子序列时,称c时a和b的公共子序列,最长公共子序列时所有子序列中长度最长的。 注意**子序列**是在原序列中删去若干元素后得到的序列,注意子序列≠子串,子串在原序列中是连续的。 比如序列a=\{1,3,2,5,4\}和b=\{1,4,2,5,3\}的LCS=\{1,2,5\},**用 d p \[ i \] \[ j \] dp\[i\]\[j\] dp\[i\]\[j\]表示子序列 a i a\_i ai和 b j b\_j bj的最长公共子序列长度**,当 a i = b j a\_i = b\_j ai=bj时,找到 a i − 1 a\_\{i-1\} ai−1和 b j − 1 b\_\{j-1\} bj−1的最长公共子序列,然后在其尾部加上 a i a\_i ai即可得到a和b的LCS;当 a i ≠ b j a\_i \\neq b\_j ai=bj时,求解两个子问题:① a i − 1 a\_\{i-1\} ai−1和 b j b\_j bj的LCS,② a i a\_i ai和 b j − 1 b\_\{j-1\} bj−1的LCS,然后取最大值,复杂度为 O ( n m ) O(nm) O(nm)。 d p \[ i \] \[ j \] = \{ d p \[ i − 1 \] \[ j − 1 \] + 1 a i = b j max ( d p \[ i − 1 \] \[ j \] , d p \[ i \] \[ j − 1 \] ) a i ≠ b j dp\[i\]\[j\]= \\begin\{cases\} dp\[i-1\]\[j-1\]+1& \{a\_\{i\}=b\_\{j\}\} \\\\ \\max(dp\[i-1\]\[j\],dp\[i\]\[j-1\])& \{a\_\{i\} \\neq b\_\{j\}\} \\end\{cases\} dp\[i\]\[j\]=\{ dp\[i−1\]\[j−1\]\+1max(dp\[i−1\]\[j\],dp\[i\]\[j−1\])ai=bjai=bj [HDU-1159 Common Subsequence][] > **Problem Description** > A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, …, xm> another sequence Z = <z1, z2, …, zk> is a subsequence of X if there exists a strictly increasing sequence <i1, i2, …, ik> of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y. > The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line. > **Sample Input** > abcfbc abfcab > programming contest > abcd mnp > **Sample Output** > 4 > 2 > 0 #include<bits/stdc++.h> using namespace std; const int maxn = 1003; char a[maxn], b[maxn]; int dp[maxn][maxn]; int main() { while (~scanf("%s%s", a + 1, b + 1)) { memset(dp, 0, sizeof(dp)); int len1 = strlen(a + 1); int len2 = strlen(b + 1); for (int i = 1; i <= len1; i++) for (int j = 1; j <= len2; j++) if (a[i] == b[j])dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); printf("%d\n", dp[len1][len2]); } return 0; } //滚动数组版后文有 # L I S LIS LIS # -------------------- **LIS(Longset Increasing Subsequence)最长递增子序列**。给定一长度为n的数组,找出一个最长的单调递增子序列。 例如A=\{5,6,7,4,2,8,3\}的最长递增子序列是\{5,6,7,8\},长度为4。 **法一** 借助前面讲的LCS,对数组A排序后得到A’,那么A的LIS就是A和A’的LCS,其复杂度是 O ( n 2 ) O(n^2) O(n2)。 **法二** 定义**dp\[i\]表示以第i个数结尾的最长递增子序列长度**,那么 d p \[ i \] = m a x ( d p \[ j \] + 1 , 0 ) , 0 < j < i , A j < A i dp\[i\]=max(dp\[j\]+1,0),0<j<i,A\_j~<A\_i dp\[i\]=max(dp\[j\]\+1,0),0<j<i,Aj <Ai 最后答案是max\{dp\[i\]\},其复杂度也是 O ( n 2 ) O(n^2) O(n2)。 **法三** 其实不算DP算法,转换思维通过辅助数组统计LIS的长度,其复杂度是 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))。 定义:辅助数组 d \[ \] d\[\] d\[\],原序列 h i g h \[ \] high\[\] high\[\], l e n len len=数组 d d d内数据个数 初始化: d \[ 1 \] = h i g h \[ 1 \] , l e n = 1 d\[1\]=high\[1\],len=1 d\[1\]=high\[1\],len=1 步骤:遍历 h i g h \[ \] high\[\] high\[\],①如果 h i g h \[ k \] > d \[ \] high\[k\]>d\[\] high\[k\]>d\[\]末尾数字,就加到 d d d后面;②否则替换 d \[ \] d\[\] d\[\]中第一个大于它的数字。 比如 h i g h \[ \] high\[\] high\[\]=\{1,5,6,2,3,4\} <table> <thead> <tr> <th>high[]</th> <th>d[]</th> <th>len</th> </tr> </thead> <tbody> <tr> <td>1 5 6 2 3 4</td> <td>1</td> <td>1</td> </tr> <tr> <td>1 5 6 2 3 4</td> <td>1 5</td> <td>2</td> </tr> <tr> <td>1 5 6 2 3 4</td> <td>1 5 6</td> <td>3</td> </tr> <tr> <td>1 5 6 2 3 4</td> <td>1 2 6</td> <td>3</td> </tr> <tr> <td>1 5 6 2 3 4</td> <td>1 2 3</td> <td>3</td> </tr> <tr> <td>1 5 6 2 3 4</td> <td>1 2 3 4</td> <td>4</td> </tr> </tbody> </table> 结束后len=4,即LIS长度为4。 [HDU-1257 最少拦截系统 ][HDU-1257 _] > **Problem Description** > 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. > 怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统. > **Input** > 输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔) > **Output** > 对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统. > **Sample Input** > 8 389 207 155 300 299 170 158 65 > **Sample Output** > 2 #include<bits/stdc++.h> using namespace std; const int maxn = 10004; int n, high[maxn]; int LIS1() { //法一 int high2[maxn],dp[2][maxn] = { 0 };//滚动数组 memcpy(high2, high, sizeof(high)); sort(high2 + 1, high2 + n + 1); for (int i = 1; i <= n; i++) //LCS for (int j = 1; j <= n; j++) if (high[i] == high2[j]) dp[i & 1][j] = dp[i & 1 ? 0 : 1][j - 1] + 1; else dp[i & 1][j] = max(dp[i & 1 ? 0 : 1][j], dp[i & 1][j - 1]); return dp[n&1][n]; } int LIS2() { //法二 int dp[maxn], ans = 1; for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = 1; j < i; j++) if (high[j] < high[i]) dp[i] = max(dp[j] + 1, dp[i]); ans = max(ans, dp[i]); } return ans; } int LIS3() { //法三 int d[maxn], len = 1; d[1] = high[1]; for (int i = 2; i <= n; i++) if (high[i] > d[len]) d[++len] = high[i]; else { //用lower_bound()查询第一个>high[i]的地址 int j = lower_bound(d + 1, d + len + 1, high[i]) - d; d[j] = high[i]; } return len; } int main() { while (cin>>n) { for (int i = 1; i <= n; i++) cin >> high[i]; //cout << LIS1() << "\n"; //cout << LIS2() << "\n"; cout << LIS3() << "\n"; } return 0; } > **原创不易,请勿转载**(本不富裕的访问量雪上加霜 ) > 博主首页:[https://blog.csdn.net/qq\_45034708][https_blog.csdn.net_qq_45034708] > *如果文章对你有帮助,记得关注点赞收藏❤* [HDU-1159 Common Subsequence]: https://vjudge.net/problem/HDU-1159/origin [HDU-1257 _]: http://acm.hdu.edu.cn/showproblem.php?pid=1257 [https_blog.csdn.net_qq_45034708]: https://blog.csdn.net/qq_45034708
相关 动态规划 一:概念: 和分冶法相似,不同之处在于前者是把问题划分为互不相交的子问题,而动态规划会出现子问题重叠的情况。通常用来求解最优化问题。。 基本步骤: ①:刻画一个最优 我就是我/ 2022年12月01日 11:51/ 0 赞/ 21 阅读
相关 动态规划 -------------------- 动态规划的设计思想 动态规划(DP)\[1\]通过分解成子问题解决了给定复杂的问题,并存储子问题的结果,以避免再次计算相同的结 柔情只为你懂/ 2022年09月25日 11:15/ 0 赞/ 253 阅读
相关 动态规划 作者:Hawstein 出处: [http://hawstein.com/posts/dp-novice-to-advanced.html][http_hawstein.c 淡淡的烟草味﹌/ 2022年09月24日 12:17/ 0 赞/ 200 阅读
相关 动态规划 1. 首先,动态规划不是一个特定的算法,它代表的是一种思想,一种手段 2. 动态规划方法往往用于求解“最优化问题”,能用动态规划求解的问题的前提是问题具有“最优子结构性质” 刺骨的言语ヽ痛彻心扉/ 2022年07月29日 11:46/ 0 赞/ 87 阅读
相关 动态规划 首先是概念:动态规划就是将原问题划分为简单的几个小问题(有点类似与分治法?但是分治法中的各个小问题是相互独立的,彼此之间不会产生影响,但是动态规划中所得的值和前面相关,当前的解 青旅半醒/ 2022年07月12日 05:01/ 0 赞/ 315 阅读
相关 动态规划 > 给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A=”1A2C3D4B56”,B=”B1D23CA45B6A”,”123456”或者”12C4B6”都是最 以你之姓@/ 2022年06月07日 00:41/ 0 赞/ 310 阅读
相关 动态规划 基本思想: 动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 区别: 与 ゞ 浴缸里的玫瑰/ 2022年05月25日 09:44/ 0 赞/ 443 阅读
相关 动态规划 等我有时间了,一定要把《算法导论》啃完,这本书的印刷质量实在太好了,就是烧脑子,滑稽。 适合应用动态规划求解的最优化问题应该具备两个要素: 最优子结构:一个问题的最优解包含 短命女/ 2022年05月17日 09:45/ 0 赞/ 322 阅读
相关 动态规划 1.题目:最长递增子序列(Longest Increasing Subsequence) 问题描述: > 给定长度为N的数组A,计算A的最长单调递增的子序列(不一定连续) 妖狐艹你老母/ 2022年05月11日 04:56/ 0 赞/ 279 阅读
相关 动态规划 算法题中动态规划是真的难,写一篇总结,彻底解决动态规划。参考:[https://blog.csdn.net/u013309870/article/details/7519359 左手的ㄟ右手/ 2021年11月19日 14:14/ 0 赞/ 493 阅读
还没有评论,来说两句吧...