1. 程式人生 > >Blue Jeans POJ - 3080 (多個字串的最長公共子串)

Blue Jeans POJ - 3080 (多個字串的最長公共子串)

題意:

      給定n個字串,要你求出這n個字串的最長公共子串,如果存在多個輸出字典序最小的那個.

分析:

       KMP+暴力去列舉即可.

#include<stdio.h>
#include<string.h>

const int maxn = 107;
const int oo = 1e9+7;

char s[maxn][maxn];
int f[maxn];

void getFail(char *P)
{
    int m = strlen(P);
    f[0] = f[1] = 0;
    for(int i = 1; i < m; i++)//雖然字串是0到m-1,但是要求出f[m]的值
    {
        int j = f[i];
        while(j && P[i] != P[j]) j = f[j];
        f[i + 1] = P[i] == P[j] ? j + 1 : 0;
    }
}

bool find(char *T, char *P) //找到所有匹配點
{
    int n = strlen(T);
    int m = strlen(P);
    int j = 0;
    for(int i = 0; i < n; i++)
    {
        while(j && T[i] != P[j]) j = f[j];
        if(T[i] == P[j]) j++;
        if(j == m) return true;//就算j到m了,也用f[m]繼續匹配
    }
    return false;
}
int main()
{
    int T;

    scanf("%d", &T);

    while(T--)
    {
        int i, j, len, M, MaxLen=60;
        char ans[maxn] = "Z";

        scanf("%d", &M);

        for(i=0; i<M; i++)
            scanf("%s", s[i]);

        for(len=60; len>=3; len--)
        for(i=0; i<=MaxLen-len; i++)
        {///列舉第一個串的所有子串
            char b[maxn]={0};

            strncpy(b, s[0]+i, len);
            getFail(b);

            for(j=1; j<M; j++)
            {
                if(find(s[j], b) == false)
                    break;
            }

            if(j==M && strcmp(ans, b) > 0)
                strcpy(ans, b);

            if(ans[0] != 'Z' && i==MaxLen-len)
                i=100, len = 0;///跳出迴圈
        }

        if(ans[0] == 'Z')
            printf("no significant commonalities\n");
        else
            printf("%s\n", ans);
    }

    return 0;
}