动态规划 最常公共子序列问题
2016-12-05 13:04
141 查看
动态规划
前面一篇博文动态规划 矩阵连乘问题,学习了什么是动态规划,以及什么时候该用动态规划,总得来说就是:当一个问题可以被分成若干个子问题求解,且子问题可以优化子结构,存在子问题重复的时候,就可以使用动态子结构。
最长公共子序列问题
最长公共子序列的定义:我们来考虑一下如何分为子问题
设 两个序列分别为 X = {x1, x2, x3 …….xm}, Y = {y1, y2, y3 ……yn},他们的最长公共子序列为 Z = {z1, z2, z3 ….zk},那么就存在下面这几种情况:如果xm == yn == zk , 那么 Z = {z1, z2…..zk-1} 一定是 X = {x1, x2, x3 …….xm-1}, Y = {y1, y2, y3 ……yn-1}的最长公共子序列;
如果xm != yn, 且zk != xm, 那么Z = {z1, z2…..zk} 是 X = {x1, x2, x3 …….xm-1}, Y = {y1, y2, y3 ……yn} 的最长公共子序列;
如果xm != yn, 且zk != yn, 那么Z = {z1, z2…..zk} 是 X = {x1, x2, x3 …….xm}, Y = {y1, y2, y3 ……yn-1} 的最长公共子序列;
并且我们可以看到存在子问题重叠的问题
如果不太理解,可以具体代入。
这样的话,当我们问题如果遇到xm == yn的情况下,就直接解决了一个子问题,说明xm或者yn就是最长公共子序列中的最后一个,接下来我们就只需要求X = {x1, x2, x3 …….xm-1}, Y = {y1, y2, y3 ……yn-1}的序列;当xm != yn的情况下,则需要解决两个子问题,分别是zk != xm和 zk != yn的情况,然后取两种情况分别所得的最长公共子序列的最大致。
概念如果有点模糊的话,我们来举个例子:
1. 如果X = “ABCD”,Y = “ACBD”,由于xm = “D” 和 yn = “D”相等,所以我们已经得出XY的最大公共子序列的最后一个值是D;
2. 如果X = “ABDC”,Y = “ACBD”,由于xm = “C”和 yn = “D”不相等,所以我们要解决X = “ABD”,Y = “ACBD”和 X = “ABDC”,Y = “ACB”两个子问题,取两个子问题中最长的公共子序列。
递归方程
输出最长公共子序列
除了用c[i, j]来记录i到j的最长公共子序列的长度,还要用一个数组b[i][j]来记录每一个子问题的前一个子问题,然后回溯输出最长公共子序列。(图从网上摘得,如果作者不允许使用,请告知)
代码实现
#include<cstdio> #include<cstring> using namespace std; const int MAXLEN = 10000; int b[MAXLEN][MAXLEN]; int c[MAXLEN][MAXLEN]; void LCSLength(char* x, char* y, int m, int n){ //初始化0边界 int i; for(i = 0; i <= m; i++){ c[i][0] = 0; } for(i = 1; i <= n; i++){ c[0][i] = 0; } for(i = 1; i <= m; i++){ for(int j = 1; j <= n; j++){ //用0表示左上,1表示左,2表示上 if(x[i-1] == y[j-1]){ c[i][j] = c[i-1][j-1] + 1; b[i][j] = 0; }else if(c[i-1][j] > c[i][j-1]){ c[i][j] = c[i-1][j]; b[i][j] = 1; }else{ c[i][j] = c[i][j-1]; b[i][j] = 2; } } } //直观看看c数组和b数组 for(i = 0; i < m; i++){ for(int j = 0; j < n; j++){ printf("%d ", b[i][j]); } printf("\n"); } printf("\n"); for(i = 0; i < m; i++){ for(int j = 0; j < n; j++){ printf("%d ", c[i][j]); } printf("\n"); } printf("\n"); } void printLCS(char *x, int i, int j) { if(i == 0 || j == 0) return; if(b[i][j] == 0) { printLCS(x, i-1, j-1); printf("%c ", x[i-1]); } else if(b[i][j] == 1) printLCS(x, i-1, j); else printLCS(x, i, j-1); } int main(){ char x[MAXLEN] = {"ABCEOG"}; char y[MAXLEN] = {"BAEOGA"}; int m = strlen(x); int n = strlen(y); LCSLength(x, y, m, n); printLCS(x, m, n); return 0; }
结果如下:
相关文章推荐
- [算法导论]动态规划---最长公共最序列问题
- java 动态规划最大公共子序列问题
- 一个看似简单却复杂的问题:求两个字符串的 左向右匹配 所有的 最长连续的 公共子字符串( 在每个字符串中先后次序相同的) 序列
- “最长公共字符串子序列”问题的动态规划法算法
- ACM最长单调递增子序列问题(动态规划)o(n*n)C++实现
- “最长公共字符串子序列”问题的动态规划法算法
- “最长公共字符串子序列”问题的动态规划法算法
- “最长公共字符串子序列”问题的动态规划法算法
- “最长公共字符串子序列”问题的动态规划法算法
- C语言 最长子序列问题(两个序列的公共子序列)
- 求最长公共序列问题
- 吉哥系列故事——完美队形I(hdu4512,公共子序列问题)
- “最长公共字符串子序列”问题的动态规划法算法
- 公共子序列问题
- 最长上升子序列问题(动态规划)
- 两个序列最大子集公共和问题
- “最长公共字符串子序列”问题的动态规划法算法
- “最长公共字符串子序列”问题的动态规划法算法
- “最长公共字符串子序列”问题的动态规划法算法
- 动态规划求解最长公共子串问题