LCS-入门

最长公共子序列问题(longest-common-subsequence problem)
问题解释:对两个序列X,Y,求他们的长度最长的公共子序列。子序列:例如,X = {5, 6,  7},那么{5} {6} {7} {5,6} {5,7} {6,7}  {5,6,7}, 空集都是X的子序列。
暴力求解:用暴力求解,那么就要穷举X的所有子序列,然后一个个检查X的子序列是否也是Y的子序列,找到最长的公共子序列,m长度的X序列有2^m个,所以暴力方法的时间复杂度为指数阶,并不实用。

1.符号:X[i],Y[j]:X,Y序列;    c[i][j]:表示X序列前i个和Y序列前j个的LCS长度,   b[i][j]:记录i, j的走向
2.递归方程:

两个序列的LCS包含两个序列前缀的LCS,因此,LCS问题具有最优子结构性质。可用动态规划求解。
解释:举个例子,X = {A,B,C,B},Y = {A,B,A,B},LCS = {A, B, B}, 若设定LCS最后一个B为去掉,它对应的是XY最后一个B,此时X1 = {A, B, C} 是X的前缀, Y2 = {A, B, A}是Y的前缀, 这时,X2和Y2的LCS为{A, B}是X和Y的前缀。

递推公式
c[i][j] = 0;   i = 0 或 j = 0   //当有序列长度为0时是没有公共子序列的
         = c[i - 1][j - 1] + 1;  X[i] = Y[j]   //X序列第i个和Y序列第j个相等, 则加一
         = max{c[i][j - 1],   c[i - 1][j]}    //在X[i]、Y[j - 1]和X[i - 1]、Y[j]中找最长的LCS赋给c[i][j]
用次递归方法人工查找:
X = A B C B D A B
Y = B D C A B A
1.X[1]是否等于Y[1]  ,否
2.找X[2]是否等于Y[1]  或者X[1]是否等于Y[2], X[2]等于Y[1],LCS第一个为X[2]
3.X[2 + 1]是否等于Y[1 + 1], 否

。。。重复找LCS
代码:

#include<iostream>
using namespace std;
//定义c[i,j]表示x链前i个和y链前j个的LCS的长度
char X[100]; //x链
char Y[100]; //y链
int c[100][100]; //LCS个数
int b[100][100]; //记录走势,1表示i, j都减一,2表示i-1,3表示j-1 
void LCS(char X[], char Y[], int n, int m)  {  //n,m为X,Y链的长度 
	//第一步先设定临界值 
	for(int i = 0; i <= m; i++)
	    c[0][i] = 0;
	for(int i = 1; i <= n; i++)
	    c[i][0] = 0;
	//主体部分 
	for(int i = 1; i <= n; i++)
	    for(int j = 1; j <= m; 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;
			}
} 
void print(char X[], char Y[], int i, int j)  {
	if(i == 0 || j == 0)  
		return;
	if(b[i][j] == 1)  {
	    print(X, Y, i - 1, j - 1);//从后往前搜索所有的字母后再打印字母 
	    cout<<X[i];
	}
	else if(b[i][j] == 2)
	    print(X, Y, i - 1, j);
	else
	    print(X, Y, i, j - 1);
}
int main()  {
	int n, m;
	X[0] = '0'; Y[0] = '0';  //链的第0个不用,可写可不写 
	cin>>n>>m;
	for(int i = 1; i <= n; i++)
	    cin>>X[i];
	for(int i = 1; i <= m; i++)
	    cin>>Y[i];
	LCS(X,Y,n,m);
	cout<<c[n][m]<<endl;
	print(X, Y, n, m);
} 
/*
7 6
A B C B D A B
B D C A B A
*/
自学算法导论上的LCS,欢迎指错,菜鸟一枚,大神勿喷
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值