• [dp] Jzoj P1187 最大公共子串


    Description

    从一个给定的串中删去(不一定连续地删去)0个或0个以上的字符,剩下的字符按原来的顺序组成的串是该串的字串。例如:“”, “a”, “aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的字串。(例子中的串不包括引号)
    编程求N个非空串的最长公共子串的长度。
    限制:2<=N<=100:N个串中的字符只会是数字0,1,…,9或小写字母a,b,…,z;每个串非空且最多含100个字符;N个串的长度的乘积不会超过30000。
     

    Input

    文件第一行是一个整数T,表示测试数据的个数(1<=T<=10)。接下来T组测试数据。各族测试数据的第一行是一个整数Ni,表示第i数据中串的个数。各组测试数据的第2到N+1行中,每行一个串,串中不会有空格
    ,但行首和行未可能有空格,这些空格当然不算作串的一部分。

    Output

    输出T行,每行一个数,第I行的数表示第I组测试数据中Ni的非空串的最长公共子串的长度
     

    Sample Input

    1
    3
    ab
    bc
    cd
    

    Sample Output

    0

    题解

    • 题目大意:给你n个字符串,求它们的最长公共子序列
    • 显然可以用dp做
    • 我们每次可以两两找最长公共子序列,新建一个字符串s[0]来储存
    • 那么就可以直接找s[0]与s[i]的最长公共子序列
    • 然后我们发现有个问题,就是在找到最长公共子序列的长度时,如果往回找到最长公共子序列
    • 考虑记录转移状态:
    • ①x[i]==y[i],f[i][j]=f[i-1][j-1]+1
    • ②x[i]!=y[i] 且 f[i-1][j]>f[i][j-1] ,f[i][j]=f[i-1][j]
    • ③x[i]!=y[i] 且 f[i-1][j]<f[i][j-1], f[i][j]=f[i][j-1]

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 using namespace std;
     6 int len[110][110],step[110][110],t,m;
     7 char s[110][110];
     8 void dp(char s1[110],char s2[110])
     9 {
    10     memset(len,0,sizeof(len)); 
    11     memset(step,0,sizeof(step));
    12     int len1=strlen(s1),len2=strlen(s2);
    13     for (int i=1;i<=len1;i++)
    14         for (int j=1;j<=len2;j++)
    15         {
    16             if (s1[i-1]==s2[j-1])
    17             {
    18                 len[i][j]=len[i-1][j-1]+1;
    19                 step[i][j]=0;     
    20             }
    21             else 
    22                 if (len[i-1][j]>=len[i][j-1])
    23                 {
    24                     len[i][j]=len[i-1][j];
    25                     step[i][j]=1;   
    26                 }
    27                 else
    28                 {
    29                     len[i][j]=len[i][j-1];
    30                     step[i][j]=2;
    31                 }
    32         }
    33     int a=len1,b=len2,w=len[len1][len2]-1;
    34     char s3[110]={};
    35     for (int i=1;i<=len[len1][len2];i++)
    36     {
    37         while (s1[a-1]!=s2[b-1])
    38         {
    39             if (step[a][b]==0) a--,b--;
    40             else 
    41                 if (step[a][b]==1) a--; 
    42                 else b--;
    43         }
    44         s3[w]=s1[a-1]; w--;
    45         if (step[a][b]==0) a--,b--;
    46         else 
    47             if (step[a][b]==1) a--;
    48             else b--;
    49     }
    50     strcpy(s[0],s3);
    51     m=len[len1][len2];
    52 }
    53 int main()
    54 {
    55     scanf("%d",&t);
    56     for (int k=1;k<=t;k++)
    57     {
    58         int n,o=0;
    59         scanf("%d",&n);
    60         for (int i=0;i<=n-1;i++) scanf("%s",s[i]);
    61         for (int i=1;i<=n-1;i++)
    62         {
    63             dp(s[0],s[i]);
    64             if (m==0&&o!=1) 
    65             {
    66                 o=1;
    67                 printf("0
    ");
    68             }
    69         }
    70         if (o==0) printf("%d
    ",m);
    71     }
    72 }
  • 相关阅读:
    ACdream 1069 无耻的出题人
    ACdream 1064 完美数
    ACdream 1028 Path
    ACdream 1020 The Game about KILL
    ACdream 1015 Double Kings
    CodeForces
    Codeforces 390A( 模拟题)
    Codeforces 389B(十字模拟)
    Codeforces 389A (最大公约数)
    Codeforces 417 C
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9323934.html
Copyright © 2020-2023  润新知