动态规划——最长公共子序列问题(LCS)
2016-07-16 16:38
447 查看
动态规划——最长公共子序列问题(LCS)
最长公共子序列问题(LCS)。给两个子序列A和B,如图9-7所示。求长度最大的公共子序列。例如1, 5, 2, 6, 8, 7和2, 3, 5, 6, 9, 8, 4的最长公共子序列为5, 6, 8(另一个解是2, 6, 8)。算法设计
该算法是动态规划——基本思想中的前缀动态规划问题,输入为x1,x2,…xn和y1,y2,…yn,子问题为x1,x2,…,xi和y1,y2,…,yj递归方程
假设z1,z2,…,zp为最大公共子序列,zk为当前比较位置,则递归方程如下:dp(n,m)=⎧⎩⎨⎪⎪0,dp(n−1,m−1)+1,dp(n−1,m),dp(n,m−1), if n=0 or m=0 if xn=ym if zk≠xn and zk=ym if zk=xnandzk≠ym
可以使用记忆搜索的方式实现。
状态
dp(i,j)表示前xi与前yj个序列的最大公共子序列长度状态转移方程
dp(i,j)={dp(i−1,j−1)+1,max(dp(i−1,j),dp(i,j−1)) if xi=yj others初始化条件
01 for i <- 0 to n 02 dp[i][0] <- 0 03 for j <- 0 to m 04 dp[0][j] <- 0
算法实现
const int MAX_NUM = 10000 + 5; // 两个序列的长度 int n, m; // 序列 int X[MAX_NUM]; int Y[MAX_NUM]; // dp(i,j)表示前xi与前yi个序列的最大公共子序列长度 int dp[MAX_NUM][MAX_NUM]; void solve() { for(int i = 0; i <= n; i++) { for(int j = 0; j <= m; j++) { // 边界 if(i == 0 || j == 0) { dp[i][j] = 0; continue; } // 状态转移方程 if(X[i] == Y[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); } } } // 获取路径 int maxLength = dp [m]; int xSubSeqPos[maxLength]; int ySubSeqPos[maxLength]; for(int i = n, j = m, k = maxLength - 1; i > 0 && j > 0;) { if(dp[i][j] == dp[i - 1][j]) { i--; } else if(dp[i][j] == dp[i][j - 1]) { j--; } else { xSubSeqPos[k] = i; ySubSeqPos[k--] = j; i--; j--; } } for(int i = 0; i < maxLength; i++) { cout << X[xSubSeqPos[i]] << "(" << xSubSeqPos[i] << "," << ySubSeqPos[i] << ") "; } cout << endl; cout << dp [m] << endl; }
测试主程序
#include <iostream> #include <algorithm> using namespace std; const int MAX_NUM = 10000 + 5; // 两个序列的长度 int n, m; // 序列 int X[MAX_NUM]; int Y[MAX_NUM]; // dp(i,j)表示前xi与前yi个序列的最大公共子序列长度 int dp[MAX_NUM][MAX_NUM]; void solve() { for(int i = 0; i <= n; i++) { for(int j = 0; j <= m; j++) { // 边界 if(i == 0 || j == 0) { dp[i][j] = 0; continue; } // 状态转移方程 if(X[i] == Y[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); } } } // 获取路径 int maxLength = dp [m]; int xSubSeqPos[maxLength]; int ySubSeqPos[maxLength]; for(int i = n, j = m, k = maxLength - 1; i > 0 && j > 0;) { if(dp[i][j] == dp[i - 1][j]) { i--; } else if(dp[i][j] == dp[i][j - 1]) { j--; } else { xSubSeqPos[k] = i; ySubSeqPos[k--] = j; i--; j--; } } for(int i = 0; i < maxLength; i++) { cout << X[xSubSeqPos[i]] << "(" << xSubSeqPos[i] << "," << ySubSeqPos[i] << ") "; } cout << endl; cout << dp [m] << endl; } int main() { while(cin >> n && n) { cin >> m; for(int i = 1; i <= n; i++) { cin >> X[i]; } for(int j = 1; j <= m; j++) { cin >> Y[j]; } solve(); } return 0; }
输出数据
6 7 1 5 2 6 8 7 2 3 5 6 9 8 4 5(2,3) 6(4,4) 8(5,6) 3 7 6 1 2 3 2 4 1 2 2 4 3 1 2 1 2(2,1) 3(3,3) 2(4,5) 1(6,6) 4 0 Process returned 0 (0x0) execution time : 2403.125 s Press any key to continue.
相关文章推荐
- C++动态规划之最长公子序列实例
- C++动态规划之背包问题解决方法
- C#使用动态规划解决0-1背包问题实例分析
- N天测试网络视频会议系统
- 动态规划
- C++ 动态规划
- 最长公共字串
- 动态规划解决背包问题的核心思路
- DP(动态规划) 解游轮费用问题
- 动态规划的用法——01背包问题
- 动态规划的用法——01背包问题
- 《收集苹果》 动态规划入门
- 《DNA比对》蓝桥杯复赛试题
- 《背包问题》 动态规划
- 自顶向下动态规划解决最长公共子序列(LCS)问题
- 01背包问题
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 关于爬楼梯的动态规划算法
- 动态规划 --- hdu 1003 **
- 91. Decode Ways 动态规划-极客学院