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

POJ #1458 Common Subsequence

时间:2018-01-30 17:07:10      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:独立   bcf   maxsize   tar   pre   重复   搜索   width   程序   

Description


 

  问题的描述以及样例在这里:1458 Common Subsequence

 

Sample


  

INPUT: 
    abcfbc               abfcab
    programming          contest 
    abcd                   mnp
OUTPUT:
    4
    2
    0

 

思路


 

  首先,我们可以想到用暴力法解决,一个序列的子集有 2n 个,两个子集相互比较找出相同且元素最多的子集即可。但是算法的运行时间是指数阶,肯定会TLE 的。

  可以换个角度思考,从两个序列的末尾开始比较,总结出求LCS的递归式。设序列 X、Y 分别有它们的前缀串,Xm = <x1, x2, .., xm> 、Yn = <y1, y2, .., yn> ,而序列 Z = <z1, z2, .., zk> 是 X、Y 的任意 LCS。有:

    1.如果 xm = yn ,则 zk = xm = ym ,且 zk-1 是xm-1、yn-1 的一个 LCS

    2.如果 xm != yn,那么 zk != xm 意味着 zk 是 xm-1 、yn 的一个CLS

    3.如果 xm != yn,那么 zk != yn 意味着 zk 是 xm 、yn-1 的一个CLS

  举个例子, <a, b, c> 与 <a, b>,比较两序列末尾元素 c、b,发现不匹配,那么就认为它们的 LCS是 <a, b> 与 <a, b> 的LCS,或者是 <a, b, c> 与 <a> 的 LCS,至于是哪个取决于后两者 LCS 哪个大。如果末尾元素匹配了,说明找到了 LCS中的一个元素,则让LCS+1 ,继续寻找 <a, b> 、<a>  的LCS...

  如果我们用 c[i][j] 代替zk 表示LCS的长度,i 表示序列X的长度,j 表示序列Y的长度,有如下递归式:

    技术分享图片

  写出递归的程序,但是发现其实很多子问题是重复求解的,比如 i = 6, j = 5,C[5, 5] 就被重复求解了。像这种的树型递归,我们可以采用记忆化搜索的策略解决,通俗的将就是再写一个备忘录,把求过的解都记录在里面,下一次问题重复时直接取出其中的解即可。

  这种算法的时间复杂度和互相独立的子问题个数有关,假设输入的规模是 m、n,那么相互独立的子问题有多少个呢?

  m·n 个,可以这么想: c[m][n] 是一个,c[m-1][n] 又是一个,c[m][n-1] 又是一个...

  所以,记忆化搜索算法的时间复杂度是O(mn)

#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXSIZE = 1000;
int c[MAXSIZE][MAXSIZE];

int getLCS (const string& x, const string& y,int i, int j) { //传入的是长度
    if (i == 0 || j == 0) { //长度为 0 时,表示序列为空,此时LCS = 0
        return 0;
    }
    if (c[i][j] >= 0) {
        return c[i][j];
    }
    
    if (x[i-1] == y[j-1]) { //用于比较的是下标,下标= 长度 - 1
        return c[i][j] = getLCS(x, y, i-1, j-1) + 1; 
    }
    else {
        return c[i][j] = std::max(getLCS(x, y, i-1, j), getLCS(x, y, i, j-1));
    }
}

int main(void) {
    string x,y;
    while (cin >> x >> y ) {
        memset (c, -1, sizeof(c)); //LCS可能是0,所以应初始化为-1
        int ans = getLCS(x, y, x.size(), y.size());
        cout << ans << endl;
    }
    return 0;
}

 

   其实上面的算法就是 DP 的一种,因为它满足 DP 的三个特点:

    1.将原问题分解成几个子问题

    2.所有问题只需要解决一次

    3.存储子问题的解

  但是这种自顶向下的办法,存储的空间不密集,会浪费很多空间。

 

POJ #1458 Common Subsequence

标签:独立   bcf   maxsize   tar   pre   重复   搜索   width   程序   

原文地址:https://www.cnblogs.com/Bw98blogs/p/8384342.html

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