DHU:1159 Common Subsequence

Common Subsequence
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 33697    Accepted Submission(s): 15333
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
解题思路:用动态规划求最长公共子序列。

3

问题描述

若给定序列X={x1,x2,,xm}则另一序列Z={z1,z2,,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,,ik}使得对于所有j=1,2,,k有:zj=xij。例如,序列Z={BCDB}是序列X={ABCBDAB}的子序列,相应的递增下标序列为

{2357}

•公共子序列的定义:

给定2个序列XY,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序XY的公共子序列。

3最长公共子序列的结构

设序列X={x1,x2,,xm}Y={y1,y2,,yn}的最长公共子序列为Z={z1,z2,,zk}

(1)xm=yn,则zk=xm=yn,且zk-1X   m -1Y n - 1 的最长公共子序列。 

(2)xmynzkxm,zxm-1Y的最长公共子序列。

(3)xmynzkyn                                                    zXyn-1的最长公共子序列。

由此可见,2个序列的最长公共子序列包含了这2个序列的前缀的最长公共子序列。因

此,最长公共子序列问题具有最优子结构性质。

3子问题的递归结构  由最长公共子序列问题的最优子结构性质建立子问题最优值的递归关系。用c[i][j]记录序列和的最长公共子序列的长度。其中, Xi={x1,x2,,xi}Yj={y1,y2,,yj}。当i=0j=0时,空序列是XiYj的最长公共子序列。故此时C[i][j]=0。其他情况下,由最优子结构性质可建立递归关系如下:

i=0,j=0;c[i][j]=0;

I,j>0,xi==yj,c[i][j]=c[i-1][j-1]+1;

I,j>0,xi!=yj,c[i][j]=max(c[i-1][j],c[i][j-1]);


题目代码:
#include<iostream>
#include <cstdio>
#include <cstring>
//#include <queue>
//#include <stack>
//#include <algorithm>
#define max(a,b)a>b?a:b
using namespace std;

int main()
{
    char s1[1500];
    char s2[1500];
    int dp[1500][1500];
    int i,j;
    while(scanf("%s%s",s1,s2)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        int len1=strlen(s1);
        int len2=strlen(s2);
        for(i=1;i<=len1;i++)
            for(j=1;j<=len2;j++)
            {
                if(s1[i-1]==s2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        printf("%d\n",dp[len1][len2]);
    }
    return 0;
}

### 回答1: 这道题目给定一个定序列的子序列是在该序列中删去若干元素后得到的序列。确定地说,若给定序列x=<x1,x2,…,xm>,则另一个序列z=<z1,z2,…,zk>,使得x的子序列为z,当且仅当z是在一割格递增的下标序列<i1,i2,…,ik>所对应的下标z1,z2,…,zk所指示的值得列表<xij,i=1,2,…,k>中得到的。例如,序列z=<b,c,d,b>是序列x=<a,b,c,b,d,a,b>的子序列,相应的递增下标序列为<i2,i3,i5,i7>,即z1,z2,z3,z4所指示的元素分别为x2,x3,x5,x7。 而要我们给定两个序列x和y,当另一个序列z的子序列是y时,称z是序列x和y的公共子序列。例如,若x=<a,b,c,b,d,a,b>,y=<b,d,c,a,b,a>,则序列<b,c,b,a>即为x和y的一个公共子序列。又,序列<b,c,b,a>也是序列y和z=<b,c,b,a>的一个公共子序列。 此外,题目还要我们找到x和y的一个最长公共子序列。换言之,我们需要找出一个序列z,使其为x和y的公共子序列,并且长度最长。 这道题目并不容易解决,常见的算法有动态规划算法和分治算法。其中动态规划算法的思想是将问题分解为更小的子问题,递归地解决这些子问题,并将它们的解组合成原问题的解。而分治算法则是将问题划分为互不相交的子问题,再将子问题的解合并起来,成为原问题的解。 因此,此题的详细解答超出了本回答的范围。建议如果需要更深入的了解,可以查询算法相关的参考书籍或网络资源。 ### 回答2: 最长公共子序列问题是一类经典的字符串匹配问题,涉及到动态规划算法。 首先,定义一个二维数组dp,其中dp[i][j]表示序列x中前i个元素和序列y中前j个元素的最长公共子序列长度。采用动态规划算法,可得到以下状态转移方程: 如果xi == yj,则dp[i][j] = dp[i-1][j-1] + 1; 如果xi != yj,则dp[i][j] = max(dp[i][j-1], dp[i-1][j]); 其中,如果xi == yj,则说明这两个字符可以构成最长公共子序列中的一个元素,那么最长公共子序列长度加1,也就是dp[i-1][j-1] + 1;如果xi != yj,则说明当前字符不能构成最长公共子序列的元素,那么最长公共子序列可能存在于序列x中前i-1个元素和序列y中前j个元素的最长公共子序列,或序列x中前i个元素和序列y中前j-1个元素的最长公共子序列中,取两者长度的最大值,即max(dp[i][j-1], dp[i-1][j])。 按照上述状态转移方程,可以用嵌套循环遍历序列x和序列y中的所有元素,计算dp数组中的所有元素的值,最终可得到dp[m][n]即为x和y的最长公共子序列长度。接着,可以反推最长公共子序列本身,从dp[m][n]开始,不断比较dp[i-1][j-1]和dp[i][j-1]以及dp[i-1][j]的大小关系,找到公共子序列的元素,从而构造出x和y的一个最长公共子序列。 总之,最长公共子序列问题可以用动态规划算法解,先计算出所有子问题的最优解,再逐步组合得到原问题的最优解,时间复杂度为O(m*n),空间复杂度为O(m*n)。 ### 回答3: 最长公共子序列问题是经典的动态规划问题。设x=<x1x2,…,xm>和y=<y1y2…,yn>两个序列,令c[i,j]表示x的前i个元素和y的前j个元素的最长公共子序列的长度,则可得出以下递推式: c[i,j]=c[i-1,j-1]+1 if xi=yj c[i,j]=max(c[i-1,j],c[i,j-1]) if xi≠yj 这里第一个递推式表示在序列x的i位置和序列y的j位置处匹配成功,则最长公共子序列的长度加一;第二个递推式表示在序列x的i位置和序列y的j位置处匹配失败,此时最长公共子序列的长度应该取决于x的前i-1个元素和y的前j个元素的最长公共子序列的长度,或x的前i个元素和y的前j-1个元素的最长公共子序列的长度,取二者中较大值即可。 利用这个递推式,可以构建一个c[m+1,n+1]的表格,其中c[0,j]=c[i,0]=0,即x和y的空序列最长公共子序列长度为0。最终答案即为c[m,n]。 此外,由于动态规划可以记录递推过程中的决策情况,因此可以利用c表格反向生成最长公共子序列,具体方法为:从c[m,n]开始,若c[i,j]=c[i-1,j],则说明当前字符在序列x中未被选用,将i减1;若c[i,j]=c[i,j-1],则说明当前字符在序列y中未被选用,将j减1;若c[i,j]=c[i-1,j-1]+1,则说明当前字符在序列x和y中均被选用,将该字符加入最长公共子序列中,同时将i和j都减1。该过程直到i或j为0结束,最终得到的即为x和y的一个最长公共子序列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值