由最长公共子序列问题的最优子结构性质建立子问题最优值的递归关系。
用c[i][j]记录序列X和Y的最长公共子序列的长度,其中, Xi={x1,x2,…,xi};Yj={y1,y2,…,yj}。
当i=0或j=0时,空序列是Xi和Yj的最长公共子序列。
故此时C[i][j]=0。其他情况下,由最优子结构性质可建立递归关系如下:
void LCSLength( int m,int n,char *x,char *y,int **c,int **b )
//c[i][j] 记录Xi和Yj 的最长公共子序列长,
{ int i,j; //b[i][j] 记录c[i][j]是由哪个子问题得到的。
for (i = 0; i <= m; i++) c[i][0] = 0; //第一列
for (i = 0; i <= n; i++) c[0][i] = 0; //第一行
for (i = 1; i <= m; i++)
for (j = 1; j <= n; j++) {
if (x[i]==y[j]) {
c[i][j]=c[i-1][j-1]+1; b[i][j]=1;} //if 左上角
else if (c[i-1][j]>=c[i][j-1])
{ c[i][j]=c[i-1][j]; b[i][j]=2;} //else if 上面
else
{ c[i][j]=c[i][j-1]; b[i][j]=3; } //else 左面
} //for 第四个for
cout<<c[m][n]<<endl;
} b,c 为 (m+1)×(n+1)的二维表
LCSLength只是计算出最优值,并未给出最优解,然而数组b可用于快速构造两个序列的最长公共子序列:
b[i][j]=1时表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列加上xi所得到的(斜);
b[i][j]=2时表示Xi和Yj的最长公共子序列是由Xi-1和Yj的最长公共子序列相同(上);
b[i][j]=3时表示Xi和Yj的最长公共子序列是由Xi和Yj-1的最长公共子序列相同。根据b的内容打印出最长公共子序列(左)。
构造最长公共子序列
void LCS(int i,int j,char *x,int **b)
{
if (i ==0 || j==0) return;
if (b[i][j]== 1){ LCS(i-1,j-1,x,b); cout<<x[i]; }(斜)
else if (b[i][j]== 2) LCS(i-1,j,x,b);(上)
else LCS(i,j-1,x,b);(左)
}
例2:序列X=(a, b, c, b, d, b),
Y=(a, c, b, b, a, b, d, b, b),
1 2 3 4 5 6 7 8 9
建立两个(m+1)×(n+1)的二维表分别存放搜索过程中得到的子序列的长度和状态。
# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
3 | 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
4 | 0 | 1 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
5 | 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 4 | 4 |
6 | 0 | 1 | 2 | 3 | 4 | 4 | 4 | 4 | 5 | 5 |
长度矩阵c
# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 3 | 3 | 3 | 1 | 3 | 3 | 3 | 3 |
2 | 0 | 2 | 2 | 1 | 1 | 3 | 1 | 3 | 1 | 1 |
3 | 0 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
4 | 0 | 2 | 2 | 1 | 1 | 3 | 1 | 3 | 1 | 1 |
5 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 3 | 3 |
6 | 0 | 2 | 2 | 1 | 1 | 3 | 1 | 2 | 1 | 1 |
状态矩阵b