最长公共子序列问题:
给定两个两个序列X= <x1, x2, ....., xm>和Y = <y1, y2, ...., yn>,希望找出X和Y的最大长度的公共子序列,可以使用动态规划来解决
定理15.1(LCS的最优子结构)
设X= <x1, x2, ....., xm>和Y = <y1, y2, ...., yn>为两个序列,并设Z = {z1, z2, ....,zk}为X和Y的任意一个LCS
(1)如果xm = yn, 那么zk = xm = yn, 而且Zk-1是Xm-1与Yn-1的一个LCS
(2)如果xm != yn,那么Zk != xm蕴含Z是Xm-1和Y的一个LCS
(3)如果xm != yn, 那么Zk != yn,蕴含Z是X和Yn-1的一个LCS
定义c[i][j]为序列Xi与Yi的一个LCS长度,则有下面递归表达式
0 若i = 0 或 j = 0;
c[i][j] = c[i-1][j-1]+1 若i, j > 0 且xi = yi;
max(c[i][j-1], c[i-1][j]) 若i,j > 0 且 xi != yi;
根据上面的递归式可以写出自底向上的动态规划代码
#include <iostream>
using namespace std;
const int m = 8;
const int n = 7;
//返回值结构
struct twoArrayPair
{
char b[m][n];
int c[m][n];
};
/*************************************************************/
/*
c[m][n]:保存了X和Y的LCS长度
b[m][n]: 帮助构造最优解
0 若i = 0 或 j = 0;
c[i][j] = c[i-1][j-1]+1 若i, j > 0 且xi = yi;
max(c[i][j-1], c[i-1][j]) 若i,j > 0 且 xi != yi;
*/
/*************************************************************/
twoArrayPair *LCSLength(char *x,a char *y)
{
twoArrayPair *twoArray = new twoArrayPair;
//c, b数组初始化
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
(twoArray->b)[i][j] = ' ';
(twoArray->c)[i][j] = 0;
}
}
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
{
if (x[i] == y[j])
{
(twoArray->c)[i][j] = (twoArray->c)[i-1][j-1]+1;
(twoArray->b)[i][j] = '\\';
}
else if ((twoArray->c)[i-1][j] >= (twoArray->c)[i][j-1])
{
(twoArray->c)[i][j] = (twoArray->c)[i-1][j];
(twoArray->b)[i][j] = '|';
}
else
{
(twoArray->c)[i][j] = (twoArray->c)[i][j-1];
(twoArray->b)[i][j] = '-';
}
}
}
return twoArray;
}
//打印LCS
void printLCS(char (*b)[n], char *x, int i, int j)
{
if (i == 0 | j == 0)
return;
if (b[i][j] == '\\')
{
printLCS(b, x, i-1, j-1);
cout << x[i];
}
else if (b[i][j] == '|')
printLCS(b, x, i-1, j);
else
printLCS(b, x, i, j-1);
}
int main()
{
char x[] = "0ABCBDAB";
char y[] = "0BDCABA";
twoArrayPair *tt = LCSLength(x, y);
cout << "x与y的最长公共子序列是:" << endl;
printLCS(tt->b, x, m-1, n-1);
cout << endl;
system("pause");
return 0;
}
运行结果为: