您的位置:首页 > 其它

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

2013-08-06 11:11 405 查看
Substrings

Time Limit: 1000MS Memory Limit: 10000K
Total 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
2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output
2
2


               题目大意:给你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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: