码迷,mamicode.com
首页 > 其他好文 > 详细

lcs

时间:2017-08-05 15:36:47      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:div   前缀   round   解决   第一个字符   bsp   cab   ack   cpp   


最长公共子序列(LCS)  ----以51nod1006为例
记:
xi x序列的前i个字符(前缀)
yj y序列的前j个字符(前缀)
假设z是LCS(x,y)

xm=yn(最后一个字符相同),则不难用反证法证明:
该字符必须是x与y的任一最长公共子序列z(设长度为k)
的最后一个字符,即zk=xm=yn 且显然有zk-1∈LCS(xm-1,yn-1)
即z的前缀zk-1是xm-1与yn-1的最长公共子序列。此时,问题转归于求
xm-1与yn-1的LCS(x,y)的长度即等于LCS(xm-1,yn-1)的长度+1;

若xm≠yn,则以不难用反证法证明:要么z∈LCS(xm-1,y),要么z∈LCS(x,yn-1).
由于zk≠xm,zk≠yn其中至少有一个必成立,若zk≠xm则有z∈LCS(xm-1,y)
,类似的,若zk≠yn则有z∈LCS(x,yn-1),此时,问题划归于求xm-1与y的LCS
及x与yn-1的LCS。LCS(x,y)的长度为:max(LCS(xm-1,y),LCS(想,yn-1))
的长度

由与上述当xm≠yn的情况时,求LCS(xm-1,y)的长度与LCS(x,yn-1)的长度
这两个问题是不相互独立
两者都需要求LCS(xm-1,yn-1)的长度。另外两个序列的LCS包含了两个序列
前缀的LCS,故问题具有最优子结构考虑用动态规划

也就是说,解决这个问题,需求:
1:LCS(xm-1,yn-1)+1;
2: LCS(xm-1,y),LCS(x,yn-1)
3:max(LCS(xm-1,y),LCS(x,yn-1))

我们定义c[i,j]表示xi和yi的LCS的长度
如果i=0或j=0,即一个序列长度为0,那么LCS为0;
根据LCS问题的最优子结构性质,可得到如下公式:


                            0                                若i=0或j=0;
                 c[i,j]=c[i-1,j-1]+1                    若i,j>0&&xi=yi
                 max(c[i-1,j],c[i,j-1])                若i,j>0&&xi≠yi

 

#include <stdio.h>
#include <iostream>
#include <string.h>
const int maxn=1005;
int dp[maxn][maxn]={0};
using namespace std;
int main(){
	char a[maxn],b[maxn],lcs[maxn];
	int i,j;
	scanf("%s %s",a,b);
	int lena=strlen(a),lenb=strlen(b);
	for(i=1;i<=lena;i++){   //i的位置固定不动,遍历j,找到i对应的字符串中与当前位置相同的元素   不好意思啦,上下写反了
		for(j=1;j<=lenb;j++){ //遍历i,找到j对应的字符串中与当前位置相同的元素,j的位置固定不动
			if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1;
			else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 
			//第一个字符串先往后移,找到与第二个字符串当前位置匹配的元素,第二个字符串先往后移
			//对这两种情况进行比较,得到最大值,存入用来存储子串的数组中                                    
			//c[i,j]=Max((c[i,j-1]),(c[i-1,j]))
		}
	}
	i=lena,j=lenb;            //以第一题为例,abcicba 与 abdkscab ,
                              //i=7,j=8;
	int len=dp[lena][lenb];  //比较结束时LCS的长度,本例为4
    lcs[len]=‘\0‘;       //lcs数组存储从0,1,2,3,‘\0‘
    while(dp[i][j]){     //dp[7][8]=4>0
	//若对应的位置不一样就根据数组通过字符串找到子串中的元素,然后赋值给要输出的字符串
		if(dp[i][j]==dp[i-1][j]) i--;     //dp[7][8]=dp[6][8] i=6;
		else if(dp[i][j]==dp[i][j-1]) j--;  //dp[7][8]=dp[7][7] j=7;
		else lcs[--len]=a[i-1],i--,j--;    
		 //不是b[i-1] 当i,j对应的位置一样时,然后把需要的值赋给要输出的字符串,
    } 
    printf("%s\n",lcs);
	return 0;
}

 

  

 

lcs

标签:div   前缀   round   解决   第一个字符   bsp   cab   ack   cpp   

原文地址:http://www.cnblogs.com/z-712/p/7290173.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!