poj 1226 Substrings(二分 + kmp)

来源:互联网 发布:繁体字转换软件 编辑:程序博客网 时间:2024/06/05 02:03
题目:http://poj.org/problem?id=1226
题目大意:给你 n 个字符串,问你他们的最长公共子串的长度,加上不同的一点就是这个最长公共串可以倒序,就是倒序的也要去匹配,然后输出。
思路:基本思想就是先找到长度最小的字符串,然后枚举它的每个子串,判断另外 n - 1个字符串是不是含有,就这样。不过,其中要有优化,首先,其实前面那个找长度最小已经是一个优化了,然后长度用二分,匹配的时候用kmp,然后就OK了!
这道题好像数据不是很强,暴力也能过,匹配的时候不用kmp,直接用 strstr 也可以(虽然我以前不知道有这个函数)。。。 = = 
说到这道题,真是说多了都是泪啊,就因为 get_fail 里那个 s[ j + 1] != s[ i ] 写成 == 了,然后 WA 了半天,自己造的数据竟然都是对的。。 T^T  另外,再提一点,这道题在hdu上也有,那个数据是真心水,怎么错的写的都是AC的,包括我这个 WA 的。。囧

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAX_N = 111;const int MAX_LEN = 111;char str[MAX_N][MAX_LEN];int fail[MAX_LEN];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[j+1] != s[i]) j = fail[j];        if(s[j+1] == s[i]) j++;        fail[i] = j;    }}char inv[MAX_LEN],pri[MAX_LEN];int kmp(char *s,int x){    get_fail(s);    int len1 = strlen(str[x]);    int len2 = strlen(s);    int j = -1;    for(int i = 0;i<len1;i++)    {        while(j >= 0 && s[j+1] != str[x][i]) j = fail[j];        if(s[j+1] == str[x][i]) j++;        if(j == len2-1) return 1;    }    return 0;}int main(){    int _;    scanf("%d",&_);    while(_--)    {        int n;        scanf("%d",&n);        int min_len = MAX_LEN;        int min_str;        for(int i = 0;i<n;i++)        {            scanf("%s",str[i]);            int len = strlen(str[i]);            if(len < min_len)            {                min_len = len;                min_str = i;            }        }        int ans = 0;        int l = 1,r = min_len;        while(l <= r)        {            int len = (l + r) >>1;            int ok = 0;            for(int i = 0;;i++)            {                int j = i + len - 1;                if(j >= min_len) break;                int cnt = 0;                for(int k = i;k<=j;k++)                    pri[cnt++] = str[min_str][k];                pri[cnt] = '\0';                cnt = 0;                for(int k = j;k>=i;k--)                    inv[cnt++] = str[min_str][k];                inv[cnt] = '\0';                int flag = 1;                for(int x = 0;x<n;x++)                    if(x != min_str)                    {                        if((!kmp(pri,x)) && (!kmp(inv,x)))                        {                            flag = 0;                            break;                        }                    }                if(flag)                {                    ok = 1;                    break;                }            }            if(ok)            {                ans = len;                l = len + 1;            }            else r = len - 1;        }        printf("%d\n",ans);    }    return 0;}


因为之前没有用过strstr,用了一下,尝尝鲜,上面的稍微改了一下,也写了一份:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAX_N = 111;const int MAX_LEN = 111;char str[MAX_N][MAX_LEN];int fail[MAX_LEN];char inv[MAX_LEN],pri[MAX_LEN];int main(){    int _;    scanf("%d",&_);    while(_--)    {        int n;        scanf("%d",&n);        int min_len = MAX_LEN;        int min_str;        for(int i = 0;i<n;i++)        {            scanf("%s",str[i]);            int len = strlen(str[i]);            if(len < min_len)            {                min_len = len;                min_str = i;            }        }        int ans = 0;        int l = 1,r = min_len;        while(l <= r)        {            int len = (l + r) >>1;            int ok = 0;            for(int i = 0;;i++)            {                int j = i + len - 1;                if(j >= min_len) break;                int cnt = 0;                for(int k = i;k<=j;k++)                    pri[cnt++] = str[min_str][k];                pri[cnt] = '\0';                cnt = 0;                for(int k = j;k>=i;k--)                    inv[cnt++] = str[min_str][k];                inv[cnt] = '\0';                int flag = 1;                for(int x = 0;x<n;x++)                    if(x != min_str)                    {                        if((!strstr(str[x],pri)) && (!strstr(str[x],inv)))                        {                            flag = 0;                            break;                        }                    }                if(flag)                {                    ok = 1;                    break;                }            }            if(ok)            {                ans = len;                l = len + 1;            }            else r = len - 1;        }        printf("%d\n",ans);    }    return 0;}