超级传送门:http://poj.org/problem?id=1226
题意要求一个最长的串X,其或其反转串rev(X)在所有串中均出现过,输出X的长度。
思路:先枚举第一个字符串的所有字串和字串的反转串,与剩下字符串进行串匹配,匹配过程中若二者有一个匹配成功则视为成功,从最长的字串开始枚举,第一个成功匹配的字串即为答案。
代码(注意reverse函数调用的位置,我之前多调用了一次导致WA):
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 105;
const int maxm = 105;
int P[maxm];
char A[maxn], B[maxm];
char S[105][maxn];
int n, m;
void preprocess(char* B, int* P, int m = -1)
{
P[0] = -1;
int j = -1;
if (m == -1)
m = strlen(B);
for (int i = 1; i < m; i++)
{
while (j != -1 && B[j + 1] != B[i])
j = P[j];
if (B[j + 1] == B[i])
j++;
P[i] = j;
}
}
int kmp(char* A, char* B, int* P, int n = -1, int m = -1)
{
int j = -1;
if (n == -1)
n = strlen(A);
if (m == -1)
m = strlen(B);
for (int i = 0; i < n; i++)
{
while (j != -1 && B[j + 1] != A[i])
j = P[j];
if (B[j + 1] == A[i])
j++;
if (j == m - 1)
return 1;
}
return 0;
}
void reverse(char* S, int len = -1)
{
if (m == -1)
m = strlen(S);
int halflen = len >> 1;
for (int i = 0; i < halflen; i++)
{
char tmp = S[i];
S[i] = S[len - i - 1];
S[len - i - 1] = tmp;
}
}
int main()
{
int x, ansLen, t, ok;
scanf("%d", &t);
while (t--)
{
scanf("%d", &x);
int len = 104;
for (int i = 0; i < x; i++)
{
scanf("%s", S[i]);
int tmpLen = strlen(S[i]);
len = len < tmpLen ? len : tmpLen;
}
ansLen = 0;
ok = 0;
for (int i = len; i >= 1 && !ok; i--)
{
for (int j = 0; j <= len - i; j++)
{
char tmp[105];
int tIndex = 0;
for (int k = j; k < j + i; k++)
tmp[tIndex++] = S[0][k];
tmp[tIndex] = '\0';
strcpy(B, tmp);
preprocess(B, P);
int y;
for (y = 1; y < x; y++)
{
int retval = kmp(S[y], B, P);
reverse(B, i);
int revretval = kmp(S[y], B, P);
if (!retval && !revretval)
break;
}
if (y == x)
{
ansLen = i;
ok = 1;
break;
}
preprocess(B, P);
for (y = 1; y < x; y++)
{
int retval = kmp(S[y], B, P);
reverse(B, i);
int revretval = kmp(S[y], B, P);
if (!retval && !revretval)
break;
}
if (y == x)
{
ansLen = i;
ok = 1;
break;
}
}
}
printf("%d\n", ansLen);
}
return 0;
}