题目链接:http://poj.org/problem?id=1226
题意:就是求n个字符串的最长公共子串,子串是可以反转的
思路:
先对字符串排个序,最短的在最前面。然后通过枚举(从长到短)每一个最短串的子串,看其或其反串是否是其他所有串的子串。
#include <stdio.h>
#include <string>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define N 101
using namespace std;
int P[N],P1[N];
bool Comp(string s1, string s2)
{
return s1.length() < s2.length();
}
void get_nextval(string ptrn, int plen, int *nextval)
{
int i = 0;
int j = -1;
nextval[0] = -1;
while(i < plen-1)
{
if(j == -1 || ptrn[i] == ptrn[j])
{
++i;
++j;
if( ptrn[i] != ptrn[j] )
nextval[i] = j;
else
nextval[i] = nextval[j];
}
else
j = nextval[j];
}
}
int kmp_search(string src, int slen, string pat, int plen, int const* nextval, int pos)
{
int i = pos;
int j = 0;
while( i < slen && j < plen)
{
if( j == -1 || src[i] == pat[j] )
{
++i;
++j;
}
else
{
j = nextval[j];
}
}
if( j >= plen )
return i-plen;
else
return -1;
}
int main(int argc, char** argv)
{
int t,m,n;
string s[101];
cin>>t;
while(t--)
{
int h;
cin>>h;
for(int i=0; i<h; i++)
cin>>s[i];
sort(s, s+h, Comp);
string a,b;
int len = s[0].length();
int flag = 0;
for(int i = len; i>0; i--)
{
for(int j=0; j<=len-i; j++)
{
a = s[0].substr(j, i);
// cout<<"a=" <<a<<endl;
b = a;
reverse(b.begin(), b.end());
m = a.length();
int k;
for(k=1; k<h; k++)
{
n = s[k].length();
// cout<<"s[k]="<<k<<" "<<s[k]<<endl;
get_nextval(a, m, P);
get_nextval(b, m, P1);
// int kmp1 = kmp_search(s[k], n, a, m, P, 0);
// cout<<kmp1<<endl;
// int kmp2 = kmp_search(s[k], n, b, m, P1, 0);
// cout<<kmp2<<endl;
if( (kmp_search(s[k], n, a, m, P, 0) == -1) && (kmp_search(s[k], n, b, m, P1, 0) == -1) )
break;
}
if(k == h)
{
flag = 1;
break;
}
}
if(flag)break;
}
if(flag)
cout<<a.length()<<endl;
else
cout<<0<<endl;
}
return 0;
}