LCS问题——动态规划

简述: LCS问题,即最长公共子序列问题,给定两个序列X={x1, x2, …, xm}和Y={y1, y2, …, yn},求X、Y最长的公共子序列。与LIS类似,LCS也是可以不连续的。

解题思路:本人觉得在这个问题上算法导论讲的很好,所以在此我主要是整理。

1、首先我们来考虑暴力搜索求解的方法,我们要暴力枚举X的所有子序列,然后再看看是不是也是Y的子序列,这样的方法,显然时间复杂度是指数级的,所以并不可取,但是,我们是否能从中看到些什么呢?

2、我们来看看LCS是不是具有最优子结构:

之前说的暴力求解,在程序中怎么表达呢?考虑一个序列Z={z1, z2, …, zk},他是X、Y的一个LCS序列:

如果xm==yn,就意味着xm肯定在Z序列里,而且是zk;

如果xm!=yn,那么说明xm和yn至多有一个在Z里面,所以这里X、Y的LCS就有两种可能性:X(1…m-1)与Y(1…n)的LCS和X(1…m)与Y(1…n-1)的LCS;

于是有最优子结构!

3、从上面就可以看出来了,没错,就是深搜!但是,太慢了。所以,记忆化一下就行了!

于是……用dp[i][j]表示X(1…i)和Y(1…j)的LCS,那么有状态转移方程

    if(x[i]==y[j])
        dp[i][j]=dp[i-1][j-1]+1;
    else
        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

完整代码:(可以用POJ_1458测试一下)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int m,n,x[1005],y[1005],ans,dp[1005][1005];
char st1[1005],st2[1005];

int main()
{
    while(~scanf("%s %s",st1,st2))
    {
        m=strlen(st1),n=strlen(st2);
        for(int i=0;i<m;i++)
            x[i+1]=st1[i];
        for(int i=0;i<n;i++)
            y[i+1]=st2[i];

        ans=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(x[i]==y[j])
                    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[m][n]);
    }

    return 0;
}

总结:

1、之前一直不知道LCS是啥,今天算是了解了一下;

2、果然深搜是王道啊!

时间: 2024-11-07 13:00:49

LCS问题——动态规划的相关文章

动态规划之最长公共子序列(LCS)

tips : 本文内容是参考了很多著名博客和自己的思考得出的,如有不当欢迎拍砖. 先简单说一下动态规划 通俗地说:动态规划就是将一个可以划分为子问题的问题进行递归求解,不过动态规划将大量的中间结果保存起来, 不管它们是否会用得到,从而在后面的递归求解过程中可以快速求解.由此可以看得出来动态规划是一个以牺牲空间 为代价换取时间的算法. 对于最长公共子序列的题目不用多说,现在来分析一下LCS的动态规划解决思路: 一.首先先观察问题是否符合动态规划最明显的两个特征:最优子结构和重叠子问题 方便起见,以

【转】最长公共子序列(LCS),求LCS长度和打印输出LCS

主要参考: 算法导论-----最长公共子序列LCS(动态规划) 其中,理解递推公式之后,要理解代码中的c数组 是怎么变化的(结合下面这个图的过程,过程为:每一行,从左到右) 该文章中,打印LCS的过程(C语言,包括递归和非递归版本)也容易看懂. Java版本可以参考:最长公共子串.最长公共子序列的Java实现与NLP应用 但打印这一部分看得不太懂: int i = 0, j = 0; while (i < substringLength1 && j < substringLen

[MOOC笔记]第一章XA 动态规划(数据结构)

Fibonacci数列和动态规划 什么是Fibonacci数列? Fibonacci数列指的是这样一个数列 {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,144, ...} 它的第0项是0,第1项是第一个1.从第二项开始,每一项都等于前两项之和.用C语言可以表示为: //Fib(n) = Fib(n-1) + fib(n-2) int Fib(int n) { return(2 > n) ? n : Fib(n-1) + Fib(n-2); } 这段代码可以计

白话算法之【动态规划入门】

什么是动态规划? 动态规划(Dynamic Programming,所以我们简称动态规划为DP)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法.20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新

动态规划问题以及诸多实例分析

开始,我先完整的分析一个动态规划问题,叫做钢条切割问题,这个问题从递归开始导入,然后引入带备忘录的自顶向下方法,最后得到动态规划的解法.所有的问题都可以遵循这样的解决方法.然后开始分析如何用递归求解动态规划问题,最后分析如何使用动态规划的解法. 钢条切割问题: 问题描述,给定一个数组,表示的是出售长度为i的钢条的价格.如p = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30] 表示的是长度为1的钢条为1美元,长度为2的钢条为5美元,以此类推. 现在有一个钢条长度为n,那么

cf#264 div2

没参加,过了好久才补齐: 第一题:好贱的题啊,题意描述不清,水又水得很. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 using namespace std; 5 int n,s,w[101]; 6 int main(){ 7 scanf("%d%d",&n,&s); 8 s=s*100; 9 int x1,y1,q=1; 10 for (int i=

POJ1080 Human Gene Functions 动态规划 LCS的变形

题意读了半年,唉,给你两串字符,然后长度不同,你可以用'-'把它们补成相同长度,补在哪里取决于得分,它会给你一个得分表,问你最大得分 跟LCS很像的DP数组 dp[i][j]表示第一个字符串取第i个元素第二个字符串取第三个元素,然后再预处理一个得分表加上即可 得分表: score['A']['A'] = score['C']['C'] = score['G']['G'] = score['T']['T'] = 5; score['A']['C'] = score['C']['A'] = -1;

非动态规划实现LCS算法

LCS(最长公共子串 longest common subsequence)一般都会采用动态规划的算法来实现,算法的时间复杂度大概是O(x2),  另外需要一个x2的额外空间, 这个算法这里我不做说明,给个讲得不错的教程地址 LCS教程 这边博文里我将给出一个不采用动态规划的算法,并且时间复杂度和动态规划算法相同,还不会使用到额外的空间,空间复杂度为O(0). 思路: 假设存在两个字符串l和r, 并且strlen(l) <= strlen(r), 将l字符串想象成一辆车, 将r字符串想象成公路,

动态规划算法之:最长公共子序列 & 最长公共子串(LCS)

1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab") b a b c 0 0 0 a 0 1