最长公共子序列

题目

最长公共子序列问题是在序列X和Y的公共子序列中查找长度最长的公共子序列,而最长公共子序列往往不止一个。
例如: X = ( A , B , C , B , D , A , B ) , Y = ( B , D , C , A , B , A ) , 则 Z = ( B , C , B , A ) , Z 1 = ( B , C , A , B ) , Z 2 = ( B , D , A , B ) , 均 属 于 L C S ( X , Y ) , 即 X , Y 的 最 长 公 共 子 序 列 有 3 个 。 X= (A,B,C,B,D,A,B),Y = (B,D,C,A,B,A),则Z = (B,C,B,A),Z_1 = (B,C,A,B),Z_2 = (B,D,A,B),均属于LCS(X,Y),即X,Y的最长公共子序列有3个。 X=(A,B,C,B,D,A,B),Y=(B,D,C,A,B,A)Z=(B,C,B,A)Z1=(B,C,A,B),Z2=(B,D,A,B),LCS(X,Y)X,Y3
定理: LCS的最优子结构性质
设序列: X = ( x 1 , x 2 , . . . . , x n ) , Y = ( y 1 , y 2 , . . . , y n ) 的 一 个 最 长 公 共 子 序 列 Z = z 1 , z 2 , . . . , z n X= (x_1,x_2,....,x_n),Y = (y_1,y_2,...,y_n)的一个最长公共子序列Z={z_1,z_2,...,z_n} X=(x1,x2,....,xn),Y=(y1,y2,...,yn)Z=z1,z2,...,zn,则:
(1)若 x m = y n , 则 z k = x m = y n , 且 Z k − 1 是 X m − 1 和 Y n − 1 x_m = y_n,则z_k=x_m=y_n,且Z_{k-1}是X_{m-1}和Y_{n-1} xm=yn,zk=xm=yn,Zk1Xm1Yn1的最长公共子序列;
(2)若 x m = ̸ y n , 则 z k = ̸ x m , 则 Z 是 X m − 1 和 Y x_m =\not y_n,则z_k =\not x_m,则Z是X_{m-1}和Y xm=yn,zk=xm,ZXm1Y的最长公共子序列;
(3)若 x m = ̸ y n , 则 z k = ̸ y n , 且 Z 是 X 和 Y n − 1 x_m =\not y_n,则z_k=\not y_n,且Z是X和Y_{n-1} xm=yn,zk=yn,ZXYn1的最长公共子序列。

建立递归关系

我们定义c[i,j]记录序列 X i X_i Xi Y j Y_j Yj的最长公共子序列的长度。
状态转移方程为:

c [ i ] [ j ] = { 0 i = 0 , j = 0 c [ i − 1 ] [ j − 1 ] + 1 i , j > 0 ; x i = y i max ⁡   { c [ i ] [ j − 1 ] , c [ i − 1 ] [ j ] } i , j > 0 ; x i = ̸ y i c[i][j] = \begin{cases} 0 & i = 0,j = 0 \\ c[i-1][j-1]+1 & i,j>0;x_i = y_i \\ \max\ \{{c[i][j-1], c[i-1][j]}\} & i,j>0;x_i =\not y_i \end{cases} c[i][j]=0c[i1][j1]+1max {c[i][j1],c[i1][j]}i=0j=0i,j>0;xi=yii,j>0;xi=yi

代码

#include<stdio.h>

#define NUM 100
int c[NUM][NUM];//记录序列Xi和Yj的最长公共子序列的长度 
int b[NUM][NUM];//用来记录比较情况 
void LCSLength(int m, int n, const char x[],char y[])//计算最优值 
{  
	int i,j;
	for (i = 1; i <= m; i++) c[i][0] = 0;//第0列全为0(此时Y序列长度为0) 
	for (i = 1; i <= n; i++) c[0][i] = 0;//第0行全为0(此时X序列长度为0)
	for (i = 1; i <= m; i++)
	for (j = 1; j <= n; j++) 
	{
		if (x[i]==y[j]) //①i,j>0且Xi与Yj相等 
		{	
			c[i][j]=c[i-1][j-1]+1; 
			b[i][j]=1;
		}else if (c[i-1][j]>=c[i][j-1]) {//②max c[i-1][j],i,j>0,Xi不等于Yj 
			c[i][j]=c[i-1][j]; 
			b[i][j]=2; 
		}else { //③max c[i][j-1],i,j>0,Xi不等于Yj 
			c[i][j]=c[i][j-1]; 
			b[i][j]=3; 
		}
	}
}

void LCS(int i,int j,char x[])// 构造最优解结构(递归) 
{
	if (i ==0 || j==0) return;
	if (b[i][j]== 1){ LCS(i-1,j-1,x); printf("%c",x[i]); }
	else if (b[i][j]== 2) LCS(i-1,j,x);
	else LCS(i,j-1,x);
}

int main() 
{
	char x[NUM];
	char y[NUM];
	int m, n;
	scanf("%d\n", &m);
	for (int i=1; i<=m; i++)//读取X序列 
		scanf("%c", &x[i]);
	scanf("%d\n", &n);
	for (int i=1; i<=n; i++)//读取Y序列 
		scanf("%c", &y[i]);
	LCSLength(m, n, x, y);
	printf("%d\n", c[m][n]);//输出最优值
	LCS(m,n,x);//输出最优解结构(此时x和y都无所谓) 
	return 0;
} 

输入

7
ABCBDAB
6
BDCABA

输出

4
BCBA

总结

怎么讲呢,学到了很多Markdown公式的写法,而矩阵连乘积正是动态规划的一个经典例子。学好动态是算法的一个深化吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值