poj 3080 Blue Jeans ( 二分 + kmp)

来源:互联网 发布:it项目招标书 编辑:程序博客网 时间:2024/05/17 03:17
题目:http://poj.org/problem?id=3080
题目大意:给你m个由A、T、C、G组成的字符串,然你找出他们字典序最小的最长的公共子串,如果长度<3,就输出那句话。
思路:先找一个长度最小的,二分长度,然后枚举子串,然后再枚举m个字符串,kmp匹配,就这样。感觉kmp的初学者来做这道题很不错。。

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 66;int fail[MAXN];void get_fail(char *s){    int len =strlen(s);    fail[0] = -1;    int j = -1;    for(int i = 1;i<len;i++)    {        while(j >= 0 && s[i]!=s[j+1]) j = fail[j];        if(s[i] == s[j+1]) j++;        fail[i] = j;    }}int kmp(char *s,char *t){    get_fail(s);    int len1 = strlen(t);    int len2 = strlen(s);    for(int i = 0,j = -1;i<len1;i++)    {        while(j >=0 && s[j+1] != t[i]) j = fail[j];        if(s[j+1] == t[i]) j++;        if(j == len2 - 1) return 1;    }    return 0;}char str[11][MAXN];char p[MAXN];char ans[MAXN];int main(){    int _;    scanf("%d",&_);    while(_--)    {        int m;        scanf("%d",&m);        int min_len = 111;        int x;        for(int i = 0;i<m;i++)        {            scanf("%s",str[i]);            int len = strlen(str[i]);            if(len < min_len)            {                min_len = len;                x = i;            }        }        ans[0] = '\0';        int l = 1,r = min_len;        while(l <= r)        {            int mid = (l+r) >>1;            int ok = 0;            int first = 1;            for(int i = 0;i<min_len;i++)            {                int j = i + mid - 1;                if(j >= min_len) break;                int cnt = 0;                for(int k = i;k <= j; k++)                    p[cnt++] = str[x][k];                p[cnt] = '\0';                int flag = 1;                for(int k = 0;k<m;k++)                    if(k != x)                    {                        if(!kmp(p,str[k]))                        {                            flag = 0;                            break;                        }                    }                if(flag)                {                    ok = 1;                    if(first || strcmp(ans,p) > 0)                    {                        strcpy(ans,p);                        first = 0;                    }                }            }            if(ok)            {                l = mid + 1;            }            else r = mid - 1;        }        int ans_len = strlen(ans);        if(ans_len >= 3) puts(ans);        else puts("no significant commonalities");    }    return 0;}