现在的位置: 首页 > 综合 > 正文

两个序列的最长公共子序列

2019年10月16日 ⁄ 综合 ⁄ 共 1168字 ⁄ 字号 评论关闭

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;
}

抱歉!评论已关闭.