题目链接:HDU1238
2 3 ABCD BCDFF BRCD 2 rose orchid
2 2
题意:给出一些字符串,问其中公共的最长子串的长度是多少,这里公共的子串是指子串本身或子串的反串在每个字符串中都出现过。
题目分析:可以先给字符串按长短排好序,然后枚举子串分别用正串和反串进行KMP,取最长的纪录长度。
这里也可以优化一下,比如正串失配再比较反串,KMP的函数可以整合到一起,不通过排序直接找长度最小的处理(不知道能不能变快),不过题目数据太弱了,怎么搞都是0ms,也没啥优化的必要。
// // main.cpp // HDU1238(1 // // Created by teddywang on 16/5/13. // Copyright © 2016年 teddywang. All rights reserved. // #include <iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; struct str{ char ss[110]; int len; }s[110]; int next1[110],next2[110]; char t1[110],t2[110]; int n,m; bool cmp(str a,str b) { if(a.len!=b.len) return a.len<b.len; else { return strcmp(a.ss,b.ss)<1; } } void getnext(char *t1,char *t2) { int i=0,j=-1; next1[0]=-1;next2[0]=-1; int len=strlen(t1); while(i<len) { if(j==-1||t1[i]==t1[j]) { if(t1[++i]==t1[++j]) next1[i]=next1[j]; else next1[i]=j; } else j=next1[j]; } i=0;j=-1; while(i<len) { if(j==-1||t2[i]==t2[j]) { if(t2[++i]==t2[++j]) next2[i]=next2[j]; else next2[i]=j; } else j=next2[j]; } } int kmp1(char *s,char *t) { int i=0,j=0; int len1=strlen(s),len2=strlen(t); while(i<len1&&j<len2) { if(j==-1||s[i]==t[j]) { i++;j++; if(j==len2) return 1; } else j=next1[j]; } return 0; } int kmp2(char *s,char *t) { int i=0,j=0; int len1=strlen(s),len2=strlen(t); while(i<len1&&j<len2) { if(j==-1||s[i]==t[j]) { i++;j++; if(j==len2) return 1; } else j=next2[j]; } return 0; } int main() { cin>>m; while(m--) { cin>>n; for(int i=0;i<n;i++) { scanf("%s",s[i].ss); s[i].len=strlen(s[i].ss); } sort(s,s+n,cmp); int maxlen=0; for(int i=0;i<s[0].len;i++) { int l=0; for(int j=i+1;j<=s[0].len;j++) { int flag=0; while(l<j-i) t1[l++]=s[0].ss[i+l]; for(int k=0;k<l;k++) t2[k]=t1[l-k-1]; t1[l]=t2[l]='\0'; getnext(t1,t2); for(int k=1;k<n;k++) { if(kmp2(s[k].ss,t2)==0&&kmp1(s[k].ss,t1)==0) { flag=1; break; } } if(flag==1) break; else if(l>maxlen) maxlen=l; } } cout<<maxlen<<endl; } }