最长公共子序列--动态规划入门
求两个序列 X{1,2, 5, 4, 。。。}和Y{1, 5, 4,,,,}中最长的共有序列。 例如X = {A,B, C, B,D, A, B}, Y={B,D,C,A,B,A} 两者的最长公共子序列为 {B,C,B, A}
分析:
这个问题是否可以分成一段一段处理呢? (即可否找出递归结构, 可见递归很重要, 也许你感觉它很基础,其实它很深奥!)。我们从X,Y的最后一个元素来考虑, 若X的最后一个元素在最长子串中(即它对最长子串有贡献), 那么有两种情况, 它和Y的最后一个元素相同, 或它与Y最后一个对最长子串有贡献的元素相等(你也许会说, 这个SB也知道, 但它偏偏很重要)。 另 c[i][j] 记录从 Xi和Yj的公共最长子序列。(这类题都是他妈的,这一个怂样,不要问我为什么)。
于是乎, 关键的递归公式横空出世。
当 i= 0, 或 j = 0 时, c[i][j ] = 0;
当i, j>0, xi = yj 时, c[i][j] = c[i-1][j-1] + 1;
当i,j>0, xi != yj 时, c[i][j] = {c[i][j-1], c[i-1][j]} --->就是由那个SB都知道的东西推来的!!嘿嘿!
#include<iostream> #include<cstring> using namespace std; const int maxn = 100+5; int b[maxn][maxn]; char x[maxn], y[maxn]; //用b[][]来记录取得最优值的路径。 int lcsLength(char x[maxn], char y[maxn], int b[maxn][maxn])//计算最优解。 { int m = x.length - 1; int n = y.length - 1; int c[m+1][n+1]; for(int i=1; i<=m; i++) c[i][0] = 0; for(int i=1; i<=n; i++) c[0][i] = 0; for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) { if(x[i]==y[j]) { c[i][j] = c[i-1][j-1] + 1; b[i][j] = 1; } else if(c[i-1][j]>=c[i][j-1]) { c[i][j] = c[i-1][j]; b[i][j] = 2; } else { c[i][j] = c[i][j-1]; b[i][j] = 3; } } return c[m][n]; } //构造最优子序列。 void lcs(int i, int j, char x[maxn], int b[maxn][maxn]) { if(i==0||j==0) return; if(b[i][j]==1) { lcs(i-1, j-1, x, b);//又是递归, 看到了吧!! printf("%c", x[i]); } else if(b[i][j]==2) lcs(i-1, j, x, b); else lcs(i, j-1, x, b); } int main() { /* 读入字符串x,y时从1读*/ }