[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\n");
68             }
69         }
70         if (o==0) printf("%d\n",m);
71     }
72 }

 

转载于:https://www.cnblogs.com/Comfortable/p/9323934.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值