题目:http://poj.org/problem?id=3080
题意:给定m个字符串,长度都为60,且只有ACGT四种字符,问这m个串的最长公共串是什么,若有多个,输出字典序最小的那个,长度小于3的输出no significant commonalities
思路:枚举第一个字符串的,每次去掉首部一个字符,然后用kmp去匹配剩下的所有字符串,求得所有公共长度的最小值,然后取其中的最大值,记得判断字典序的问题,刚开始没看到,心痛。。。直接暴力也能过
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 110;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;
int nt[N];
int m;
char s[N][N];
set<string> ste;
void getnt(char s[])
{
int i = 0, j = -1;
nt[0] = -1;
while(s[i])
{
if(j == -1 || s[i] == s[j])
{
i++, j++;
if(s[i] != s[j]) nt[i] = j;
else nt[i] = nt[j];
}
else j = nt[j];
}
}
int kmp(char s1[], char s2[])
{
int i = 0, j = 0;
int cnt = 0;
while(s1[i])
{
if(j == -1 || s1[i] == s2[j])
i++, j++;
else j = nt[j];
cnt = max(cnt, j);
if(j != -1 && !s2[j]) break;
}
return cnt;
}
P solve()
{
int len = 60;
int res = 0, k = 0;
for(int i = 0; i + 3 <= len; i++)
{
getnt(s[0] + i);
int ans = INF;
for(int j = 1; j < m; j++)
{
int cnt = kmp(s[j], s[0] + i);
ans = min(cnt, ans);
}
if(res < ans)
res = ans, k = i;
else if(res == ans)
{
if(strncmp(s[0] + k, s[0] + i, res) > 0)
k = i;
}
}
return make_pair(k, res);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ste.clear();
scanf("%d", &m);
for(int i = 0; i < m; i++)
scanf(" %s", s[i]);
P p = solve();
if(p.second < 3)
printf("no significant commonalities\n");
else
{
for(int i = p.first; i < p.first + p.second; i++)
printf("%c", s[0][i]);
printf("\n");
}
}
return 0;
}