最长公共子序列(动态规划)
图片以及参考来源
最长公共子序列:LCS(Longest common subsequence)
设X={X1,X2,X3,X4…,Xm},Y={Y1,Y2,Y3,Y4…,Yn},Z={Z1,Z2,Z3,Z4…,Zk}是他们的最长公共子序列
分析可知:
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存x,y的最长公共子序列,二维数组b存值的来源。
我们假设二维数组c的横坐标为序列x,纵坐标为序列y,且都有一个第0列和第0行,因为空序列与任何序列都为空。
c[2][4]=1的含义是序列x的子序列AB 与 序列y的子序列BDCA最长公共子序列=1.
#include <string.h>
#include <iostream>
using namespace std;
#define MAXSIZE 100
int c[MAXSIZE][MAXSIZE]; //二维数组c存两个序列最大公共子序列中元素个数
int b[MAXSIZE][MAXSIZE]; //数组b存两个序列最大公共子序列中元素个数是从哪来的
void LCSLength( int xLength, int yLength, char *x, char *y ) {
//二维数组c第一列置0
for( int i = 0; i <= xLength; i++ ) {
c[i][0] = 0;
}
//二维数组c第一行置0
for( int i = 0; i <= yLength; i++ ) {
c[0][i] = 0;
}
//填充表格
for( int i = 1; i <= xLength; i++ ) {
for( int j = 1; j <= yLength; j++ ) {
//这里x与y的下标要减一,因为x,y都是从下标0开始存。而数组c是从1开始表示的
if( x[i - 1] == y[j - 1] ) {
//如果对应元素相等,最大值 = 上一个最大子序列+1
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 1; // =1 表示由对角线得
} else if( c[i - 1][j] >= c[i][j - 1] ) { //不相等时,选c[i - 1][j]与c[i][j - 1] 较大那个
c[i][j] = c[i - 1][j];
b[i][j] = 2; //=2 表示由表中上面元素得
} else {
c[i][j] = c[i][j - 1];
b[i][j] = 3; //=3 表示由表中左面元素得
}
}
}
}
//输出最大公共子序列中元素
//递归调用 后进先出
void LCS( int i, int j, char *x ) {
if( i == 0 || j == 0 ) { //第0行或第0列的无最大子段和
return ;
}
//表格元素由对角线元素得
if( b[i][j] == 1 ) {
LCS( i - 1, j - 1, x );
cout << x[i - 1];
} else if( b[i][j] == 2 ) {
LCS( i - 1, j, x );
} else {
LCS( i, j - 1, x );
}
}
int main() {
char x[MAXSIZE], y[MAXSIZE];
int xLength ;
int yLength ;
cin >> x >> y;
xLength = strlen( x );
yLength = strlen( y );
LCSLength( xLength, yLength, x, y );
LCS( xLength, yLength, x );
//for( int i = 0; i <= xLength; i++ ) {
// for( int j = 0; j <= yLength; j++ ) {
// printf( "\t%d", b[i][j] );
// }
// cout << endl;
//}
/*for( int i = 0; i <= xLength; i++ ) {
for( int j = 0; j <= yLength; j++ ) {
printf( "\t%d", c[i][j] );
}
cout << endl;
}*/
system( "pause" );
return 0;
}