DP方式求解:
#include <iostream>
using namespace std;
/**
* 问题描述:两个字符串,求解他们的最长公共子序列,子序列不要求连续
*
* 分析这个问题,我们可以发现有子结构,可以将X,Y两个字符串的最长公共子串
* 的问题转换成更小的子问题。而且这个问题的求解过程有重叠子问题。根据这两个
* 性质我们确定尝试用DP来解决。
* 首先定义状态,f(m,n),代表字符串X以Xm结尾的子串与字符串Y以Yn结尾的子串的
* 最长公共子序列。
* 如果Xm == Yn,那么问题转换成求解f(m-1,n-1),且f(m,n) = f(m-1,n-1)+1
* 如果Xm != Yn,那么最长公共子序列要么是X(m-1)结尾的子串与Yn结尾的子串的最长公共子序列
* 要么是Xm结尾的子串与Y(n-1)结尾的子串的最长公共子序列
* 根据上面分析很容易写出状态转移方程(递推式):
* f(m,n) =
* f(m,n) = f(m-1,n-1)+1. Xm == Yn
* f(m,n) = max{f(m,n-1),f(m-1,n)}. Xm != Yn
*
* 下面代码的任务就是自底向上求解这个状态转移方程。
*/
#define M 8 //行
#define N 7 //列
int dp[M][N] = {0};
int lcs_max(int x, int y){
return x>y?x:y;
}
/**
* DP求解最长公共子序列
*/
int lcs(const char *a, const char *b){
int row = M;
int col = N;
//初始化第一行和第一列
if(a[0] == b[0]) dp[0][0] = 1;
else dp[0][0] = 0;
for(int i=1;i<N;i++){
if(a[0] == b[i]) dp[0][i] = 1;
else dp[0][i] = 0;
}
for(int j=1;j<M;j++){
if(b[0] == a[j]) dp[j][0] = 1;
else dp[j][0] = 0;
}
//核心代码:自底向上求解DP矩阵(注意a是列,b是行)
for(i=1;i<row;i++){
for(j=1;j<col;j++){
if(a[i] == b[j]) dp[i][j] = dp[i-1][j-1]+1;
else dp[i][j] = lcs_max(dp[i-1][j], dp[i][j-1]);
}
}
//输出lcs矩阵
for(i=0;i<row;i++){
for(j=0;j<col;j++){
cout<<dp[i][j];
}
cout<<endl;
}
//返回最长子序列值
return dp[row-1][col-1];
}
int main(){
char *a = "aceddbcs"; //a作为DP矩阵的列(故DP矩阵8行)
char *b = "cebsdbc"; //b作为DP矩阵的行(故DP矩阵7列)
cout<<lcs(a,b)<<endl;
return 0;
}