POJ 1226 Substrings(最长公共连续串的变形,可以倒转+KMP)

来源:互联网 发布:网络协议实践 李毅超 编辑:程序博客网 时间:2024/06/08 05:52
Substrings
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 10451 Accepted: 3598

Description

You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

Input

The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

Output

There should be one line per test case containing the length of the largest string found.

Sample Input

23ABCDBCDFFBRCD2roseorchid

Sample Output

22 

               题目大意:给你n个串,求最小公共连续子串,不过这个可以倒转,比如ro和or可以匹配

         解题思路:思路很清晰,把第一个串当模式串,分解求next匹配然后逆转求next匹配。自己的思路是先顺序找到子串,然后再找它的逆转串的相对位置。例如模式串abcdefg,我先逆转模式串放在另一个数组里面。子串可以是bcde(sta=1,len=1+4)逆转就变成了edcb(sta=7-1-4,len=7-1).这样把规律看出来就可以了。果断一A!

         题目地址:Substrings

AC代码:
#include<iostream>#include<cstring>#include<string>#include<cstdio>using namespace std;int nextp[105],nexts[105],n;char a[105][105];char b[105];  //将模式串翻转int lena0; //模式串的长度//我的思路是用第一个字符串当模式串,然后再枚举长度由大到小求next匹配void getnextp(int sta,int len)   //模式串{     int i,j;     len=sta+len;   //相对位置变成绝对位置     nextp[sta]=sta,nextp[sta+1]=sta;     for(i=sta+1;i<len;i++)     {          j=nextp[i];          while(j!=sta&&a[0][i]!=a[0][j])               j=nextp[j];          if(a[0][i]==a[0][j])               nextp[i+1]=j+1;            else               nextp[i+1]=sta;     }}void getnexts(int sta,int len)   //翻转后的模式串{     int i,j;     sta=lena0-sta-len;    //要把子串的位置转换成b的位置     len=sta+len;     nexts[sta]=sta,nexts[sta+1]=sta;     for(i=sta+1;i<len;i++)     {          j=nexts[i];          while(j!=sta&&b[i]!=b[j])               j=nexts[j];          if(b[i]==b[j])               nexts[i+1]=j+1;            else               nexts[i+1]=sta;     }}int KMP(int sta,int len){     int i,j,k;     int sta1=sta;     int sta2=lena0-sta-len;     int len1=sta+len;       int len2=sta2+len;     for(k=1;k<n;k++)   //后面的串都和第一个串的子串匹配     {          int flag=0;          j=sta1;          for(i=0;i<strlen(a[k]);i++)          {               while(j!=sta1&&a[k][i]!=a[0][j])                    j=nextp[j];               if(a[k][i]==a[0][j])                    j++;               if(j==len1)               {                  flag=1;                  break;               }          }          j=sta2;          for(i=0;i<strlen(a[k]);i++)          {               while(j!=sta2&&a[k][i]!=b[j])                    j=nexts[j];               if(a[k][i]==b[j])                    j++;               if(j==len2)               {                  flag=1;                  break;               }          }          if(flag==0)    //有一个没有匹配,便返回0               return 0;     }     return 1;}int main(){     int i,j,T,l;     scanf("%d",&T);     while(T--)     {          scanf("%d",&n);          if(n==0)             break;          for(i=0;i<n;i++)               scanf("%s",a[i]);          lena0=strlen(a[0]);          for(i=0;i<lena0;i++)               b[i]=a[0][lena0-i-1];          b[lena0]='\0';          int flag=0;          for(i=lena0;i>=1;i--)  //从长度lena0开始往下枚举          {             int flag1=0;    //长度为i的是否存在             for(j=0;j<=lena0-i;j++)  //模式串分解的起始位置             {                 getnextp(j,i);                 getnexts(j,i);                 if(KMP(j,i))                 {                     flag1=1;                     printf("%d\n",i);                     break;                 }             }             if(flag1)             {                  flag=1;                  break;             }          }          if(flag==0)            puts("0");     }     return 0;}