zoukankan      html  css  js  c++  java
  • [kuangbin带你飞]专题十二 基础DP1L

    L - Common Subsequence POJ - 1458

    题目链接:https://vjudge.net/contest/68966#problem/L

    题目:

    给定序列的子序列是给定序列,其中省略了一些元素(可能没有)。给定序列X = <x1,x2,...,xm>另一个序列Z = <z1,z2,...,zk>是X的子序列,如果存在严格增加的序列<i1,i2,..对于所有j = 1,2,...,k,x ij = zj,X的索引,...,ik>。例如,Z = <a,b,f,c>是X = <a,b,c,f,b,c>的子序列,其索引序列<1,2,4,6>。给定两个序列X和Y,问题是找到X和Y的最大长度公共子序列的长度。
    输入
        程序输入来自std输入。输入中的每个数据集包含两个表示给定序列的字符串。序列由任意数量的空格分隔。输入数据是正确的。
    产量

    Sample Input
    abcfbc         abfcab
    programming    contest 
    abcd           mnp
    Sample Output
    4
    2
    0
    思路:通过这个去看了下LCS:
    LCS是Longest Common Subsequence的缩写,即最长公共子序列。一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列
    比如,对于char x[]="aabcd";有顺序且相互相邻的aabc是其子序列,有顺序但是不相邻的abc也是其公共子序列。即,只要得出序列中各个元素属于所给出的数列,就是子序列。
    再加上char y[]="12abcabcd";对比出才可以得出最长公共子序列abcd。
    在两个字符串中,有些字符会一样,可以形成的子序列也有可能相等,因此,长度最长的相等子序列便是两者间的最长公共字序列,其长度可以使用动态规划来求。

    以s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2}为例。

    借用《算法导论》中的推导图:

    创建 DP数组C[][];
      

             图中的空白格子需要填上相应的数字(这个数字就是c[i][j]的定义,记录的LCS的长度值)。填的规则依据递归公式,简单来说:如果横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1。如果不等,取c[i-1,j] 和 c[i,j-1]的最大值。首先初始化该表:

             

              然后,一行一行地从上往下填:

             

              S1的元素3 与 S2的元素3 相等,所以 c[2,1] = c[1,0] + 1。继续填充:

              

                S1的元素3 与 S2的元素5 不等,c[2,2] =max(c[1,2],c[2,1]),图中c[1,2] 和 c[2,1] 背景色为浅黄色。

                继续填充:

                

                

                 

                   中间几行填写规则不变,直接跳到最后一行:

                  

                    至此,该表填完。根据性质,c[8,9] = S1 和 S2 的 LCS的长度,即为5。

    得到公式

    LCS代码如下(也是该题AC代码):

    
    
    //
    // Created by hanyu on 2019/8/8.
    //
    #include <algorithm>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <set>
    #include<math.h>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn=1000+7;
    #define MAX 0x3f3f3f3f
    int main()
    {
        char s[maxn],s1[maxn];
        int dp[maxn][maxn];
        while(~scanf("%s%s",s,s1))
        {
            int n=strlen(s);
            int n1=strlen(s1);
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n1;j++)
                {
                    if(s[i-1]==s1[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
    ",dp[n][n1]);
        }
        return 0;
    }
    
     
    
    
  • 相关阅读:
    《深入了解 Linq to SQL》之对象的标识 —— 麦叔叔呕心呖血之作
    闲聊吉日与水军
    谈谈需求的变更
    ALinq BUG & 版本发布
    Linq to SQL (ALinq) 也来AOP —— ALinq Inject 博客园首发
    使用Orachard与Bootstrap建站心得
    一位软件作者的吐嘈——读《Google Reader猝死启示录:互联网无法永远免费》有感
    被神化的架构和被夸大的CTRL+C、CTRL+V
    我对程序员技能的一些认识
    又见ORM跑分 —— 对ORM跑分的吐嘈
  • 原文地址:https://www.cnblogs.com/Vampire6/p/11321237.html
Copyright © 2011-2022 走看看