• BZOJ 2423 (求LCS的长度和种类数)


    Description

    字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。

    Input

    第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。
    第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。

    Output

    第1行输出上述两个最长公共子序列的长度。
    第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。
     

    Sample Input

    ABCBDAB.
    BACBBD.

    Sample Output

    4
    7
     
    反思:题目虽然看题解看懂了,自己也敲出来了,但是当别人问的时候不能清晰的讲出自己思路(甚至还讲错了,这个是真TM尴尬),这样是失败的,虽然AC了,然并卵;
       这题第2问严格的来说并不能算动态规划(不满足无后效性),只是借用其中状态如何转移;
     
    题解:第一问模板题,第二问不会写
      有2个问题:第LCS的个数,代码会爆空间(需要滚动数组)
      f[i][j]表示A前i位,B前j位的最长公共子序列长度,用g[i][j]表示A前i位,B前j位的最长公共子序列数目

      g[i][j]如何转移呢?考虑这是从那一步推过来的,
      比如当 f[i][j]=f[i−1][j],就可以认为从f[i-1][j]转移过来,
      那么g[i][j]=g[i-1][j];
      那么有如下关系式:
      当f[i][j]=f[i−1][j],g[i][j]+=g[i−1][j]

      当f[i][j]=f[i][j−1],g[i][j]+=g[i][j−1]

      当a[i]=b[j]且f[i][j]=f[i−1][j−1]+1,g[i][j]+=g[i−1][j−1],看起来好像没啥问题,but...样例都没法过,Orz

      其实是忽略了一种情况(本质上是对这个状态转移不是特别清晰),

      当a[i]≠b[j],并且f[i][j]=f[i1][j1]f[i][j]=f[i−1][j−1],(就是a,b的最后一位均没有匹配,会导致上面的2个if条件都会满足,

      g[i][j]同时累计上g[i-1][j]和g[i][j-1]时,明显有重复的情况 。

      

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 const int mod=100000000;
     7 const int maxn=5005;
     8 char a[maxn], b[maxn];
     9 int f[2][maxn],g[2][maxn];
    10 
    11 int main()
    12 {
    13     //freopen("in.txt", "r", stdin);
    14 
    15     scanf("%s",a+1);scanf("%s",b+1);
    16     int n=strlen(a+1)-1, m=strlen(b+1)-1;
    17 
    18     g[1][0]=1;
    19     for(int j=0;j<=m;j++)
    20         g[0][j]=1;
    21 
    22     for(int i=1;i<=n;i++)
    23     {
    24         int now=i&1,pre=now^1;
    25         for(int j=1; j<=m; j++)
    26         {
    27             f[now][j]=max(f[pre][j], f[now][j-1]);
    28             if(a[i]==b[j])
    29             {
    30                 f[now][j]=max(f[now][j],f[pre][j-1]+1);
    31                 if(f[now][j]==f[pre][j-1]+1)
    32                     g[now][j]=g[pre][j-1];
    33             }
    34             else
    35             {
    36                 g[now][j]=0;
    37                 if(f[now][j]==f[pre][j-1])
    38                     g[now][j]-=g[pre][j-1];
    39             }
    40             if(f[now][j]==f[pre][j])
    41                 g[now][j]=(g[now][j]+g[pre][j])%mod;
    42 
    43             if(f[now][j]==f[now][j-1])
    44                 g[now][j]=(g[now][j]+g[now][j-1])%mod;
    45         }
    46     }
    47     printf("%d
    %d",f[n&1][m],g[n&1][m]);
    48     return 0;
    49 }
  • 相关阅读:
    LeetCode--Insert Interval
    LeetCode--Surrounded Regions
    LeetCode--Container With Most Water
    LeetCode--Permutation Sequence
    NYOJ---540奇怪的排序
    NYOJ-858下三角矩阵
    素数筛选法
    NYOJ----776删除元素
    矩阵快速幂
    神奇算式
  • 原文地址:https://www.cnblogs.com/Yokel062/p/10629560.html
Copyright © 2020-2023  润新知