您的位置:首页 > 其它

动态规划——最长公共子序列问题(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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息