动态规划----公共子序列(LCS) 以hdu1159为例
动态规划----公共子序列(LCS) 以hdu1159为例
推理过程
记:
xi x序列的前i个字符(前缀)
yj y序列的前j个字符(前缀)
z=LCS(x,y)长度为k
1、若xm=yn(最后一个字符相同),则不难用反证法证明: 该字符必须是x与y序列的任一最长公共子序列z的最后一个字符,即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;
2、若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。LCS(x,y)的长度为:max(LCS(xm-1,y),LCS(x,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;
hdu 1159
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
1 class Solution(object): 2 def LCS(self, str1, str2): 3 """ 4 :type str1: str 5 :type str2: str 6 :rtype: int 7 """ 8 dp=[[0]*len1 for _ in range(len2] 9 len1,len2=str(str1),str(str2) 10 for i in range(1,len1): 11 for j in range(1,len2): 12 if str1[i]==str2[j]: 13 dp[i][j]=dp[i-1][j-1]+1 14 else: 15 dp[i][j]=max(dp[i-1][j],dp[i][j-1]) 16 return dp[len1][len2]
1 #include <bits/stdc++.h> 2 #include <stdio.h> 3 #define maxn 1005 4 #include <string> 5 #include <algorithm> 6 7 int dp[maxn][maxn]={0}; 8 using namespace std; 9 10 int comm_subsequence(char *a,char *b,int len1,int len2){ 11 for(int i=1;i<=len1;i++){ 12 for(int j=1;j<=len2;j++){ 13 if(a[i-1]==b[j-1]){ 14 dp[i][j]=dp[i-1][j-1]+1; 15 }else{ 16 dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 17 } 18 } 19 } 20 21 return dp[len1][len2]; 22 } 23 24 int main(){ 25 char a[maxn]; 26 char b[maxn]; 27 while(scanf("%s %s",a,b)!=EOF){ 28 int len1=strlen(a); 29 int len2=strlen(b); 30 memset(dp,0,sizeof(dp)); 31 int tmp=comm_subsequence(a,b,len1,len2); 32 printf("%d\n",tmp); 33 } 34 return 0; 35 }