动态规划--->2.最长公共子序列问题

动态规划

最长公共子序列问题

问题描述:
给定两个序列X={x1,x2,…,xn}和Y={y1,y2,…,yn},找出X和Y的一个最长公共子序列
说明:

  • 1.子序列:
    给定序列X={x1,x2,…,xn},Z={z1,z2,…,zn},若Z中的元素是X中的元素,当且仅当这些元素的按X原序列中的的顺序递增排列,则称Z是X的子序列
  • 2.公共子序列
    给定序列X和序列Y,序列Z是X的子序列,也是Y的子序列,则称Z是X和Y的公共子序列
  • 3.最长公共子序列
    包含元素最多的公共子序列即为最长公共子序列

最优子结构性质分析:
设Zk={z1,z2,…,zk}是序列Xm={x1,x2,…,xm}和序列Yn={y1,y2,…,yn}的最长公共子序列
1.若zk=xm=yn,则Zk-1={}是Xm-1和Yn-1的最长公共子序列
2.若xm≠yn,xm≠zk,则Zk是Xm-1和Yn的最长公共子序列
3.若xm≠yn,yn≠zk,则Zk是Xm和Yn-1的最长公共子序列

建立最优值得递归关系式:
设c[i][j]表示序列Xi和Yj的最长公共子序列的长度
在这里插入图片描述

算法设计:

  • 步骤1:确定合适的数据结构
    1.采用二维数组c来存放各个子问题的最优值,c[i][j]表示序列Xi和Yj的最长公共子序列的长度
    2.二维数组b来存放各个子问题最优解的来源(如b[i][j]=1表示c[i][j]由c[i-1][j-1]+1得到;b[i][j]=2表示c[i][j]由c[i][j-1] 得到;b[i][j]=3表示c[i][j]由c[i-1][j] 得到)
    数组x[] (长度为m)和y[] (长度为n)分别用来存放X序列和Y序列
  • 步骤2:初始化
    令c[i][0]=0,c[0][j]=0 {0≤i≦m,0≦j≦n}
  • 步骤3:循环阶段,根据递归关系式,确定序列Xi和·Yj的最长公共子序列长度,1≦i≦m
    步骤3-1:
    i=1时,,求出c[1][j],同时记录c[1][j],1≦j≦n
    步骤3-2:
    1=2时,求出c[2][j],同时记录吧b[2][j],1≦j≦n
    以此类推,直到
    步骤3-m:
    i=m时,求出c[m][j],同时记录b[m][j],1≦j≦n;此时c[m][n] 就是序列X和Y的最长公共子序列
  • 步骤4:
    根据二维数组b记录的相关信息以自底向上的方式来构造最优解
    步骤4-1:
    初始时:i=m,j=n
    步骤4-2:
    如果b[i][j]=1,则输出x[i],同时递推到b[i-1][j-1];如果b[i][j]=2,则递推到b[i][j-1];如果b[i][j]=3,则递推到b[i-1][j];
    重复执行步骤4-2,直到i=0或j=0,此时就可得到序列X和Y的最长公共子序列

c++代码:

//自底向上计算最优值,并记录相关信息
void LCSLength(){
	int i,j;
	for(i=1; i<=m; i++){
		c[i][0] = 0;
	}
	for(i=1; i<=n;i++){
		c[0][i] = 0;
	}
	for(i=1; i<=m; i++){
		for(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][j] = c[i-1][j];
				b[i][j] = 3;
			}else{
				c[i][j] = c[i][j-1];
				b[i][j] = 2;
			}
		}
	}
}

void LCS(int i,int j,char *x,int **b){
	if(i == 0 || j == 0){
		return;
	}
	if(b[i][j] == 1){
		LCS(i-1,j-1,x,b);
		cout<<x[i];
	}else if(b[][] == 2){
		LCS(i,j-1,x,b);
	}else{
		LCS(i-1,j,x,b);
	}

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值