动态规划----公共子序列(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;

上述公式是递归思想,但是实际做题中,因为时间限制,通常不会采用递归,2^n,太阔怕啦,常以牺牲空间的方式(记忆化)来增速!
----自己理解是递归是从下到上,而dp数组是从上到下 ,有点斐波那契数列的味道,理解有误的话,还请留言等方式指正!
下面一个最简单的应用吧,hdu 1159题
 

 hdu 1159

Problem Description
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is a subsequence of X if there exists a strictly increasing sequence <i1, i2, ..., ik> of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y. 
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. 
 
Sample Input
abcfbc abfcab
programming
contest abcd mnp

Sample Output
4
2
0
 
Python 题解:
 
 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]
View Code
注意scanf输入时一定要判断EOF,否则就会超时
 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 }
posted @ 2017-08-05 14:30  浅忆~  阅读(485)  评论(0编辑  收藏  举报