【扩展KMP】POJ_3450| HDU_2328 Corporate Identity

原题直通车:POJ_3450 Corporate Identity  HDU_2328 Corporate Identity

题意概述:找出N个串中最长公共子串

分析:

一、可以直接枚举其中一个串的所有字串,跟所有串进行匹配找到结果。

二、用其中一个串的每一个后缀和其它所有串分别求一次扩展KMP,并找到后缀中能在所有串中匹配到的最长前缀,最后在每个后缀的最长前缀中找出最长且字典序最小的。

代码参考:

KMP:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
const int maxn=4444;

char x[222],ans[222], f[maxn][222];
int next[222], n;

void strcpy(char *y,int i,int len){
    for(int j=0;j<len;++i,++j) x[j]=y[i];
    x[len]='\0';
}
void Get_Next(char *s){
    int len=strlen(s), i = 0, j = -1;
    next[0]=-1;
    while(i<len){
        if(j==-1||s[i]==s[j]){
            if(s[++i]==s[++j]) next[i]=next[j];
            else next[i]=j;
        }
        else j=next[j];
    }
}
bool KMP(char *s,char *a){
    int ls=strlen(s), la=strlen(a);
    Get_Next(a);
    int i=0, j=0;
    while(i<ls&&j<la){
        if(j==-1||s[i]==a[j])
            ++i,++j;
        else j=next[j];
    }
    if(j==la) return true;
    return false;
}
int main(){
    while(~scanf("%d",&n),n){
        for(int i=0; i<n; ++i) scanf("%s",f[i]);
        int len = strlen(f[0]);
        bool flag = false;
        ans[0]='\0';
        for(int i=len; i && !flag; --i)
            for(int j=0,k; j<=len-i; ++j) {
            strcpy(f[0], j, i);
            for(k=1; k<n; ++k) if( !KMP(f[k],x) ) break;
            if(k==n && (!flag || strcmp(ans,x)>0)) {
                strcpy(ans, x);
                flag=true;
            }
        }
        if(flag) puts(ans);
        else puts("IDENTITY LOST");
    }
    return 0;
}


扩展KMP:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[4005][205], f[4005][205], ans[205];
int next[205], extend[205];
void get_next(char *g) {
    int lg = strlen(g), j = 0;
    next[0] = lg;
    while(j+1<lg && g[j] == g[j+1]) ++j;
    next[1] = j;
    for(int i=2, k=1; i<lg; ++i) {
        int p = k+next[k]-1;
        int l = next[i-k];
        if(i+l < p+1) next[i] = l;
        else {
            j = (p-i+1>0 ? p-i+1 : 0);
            while(i+j<lg && g[j] == g[i+j]) ++j;
            next[i] = j;
            k = i;
        }
    }
}
int ExKMP(char *s, char *g) {
    int ls = strlen(s), lg = strlen(g), j = 0, max_len;
    while(j<lg && j<ls && s[j] == g[j]) ++j;
    max_len = extend[0] = j;
    for(int i=1, k=0; i<ls; ++i) {
        int p = k+extend[k]-1;
        int l = next[i-k];
        if(i+l < p+1) extend[i] = l;
        else {
            j = (p-i+1>0 ? p-i+1 : 0);
            while(i+j<ls && j<lg && s[i+j] == g[j]) ++j;
            extend[i] = j;
            k = i;
        }
        if(extend[i] > max_len) max_len = extend[i];
    }
    return max_len;
}
int main() {
    int n;
    while(~scanf("%d", &n) && n) {
        for(int i=0; i<n; ++i) scanf("%s", s[i]);
        int len = strlen(s[0]), max_len = -1;
        for(int i=0; i<len; ++i) {
            get_next(s[0]+i);
            int mx = -1;
            for(int j=1; j<n; ++j) {
                int ml = ExKMP(s[j], s[0]+i);
                if(mx == -1 || ml < mx) mx = ml;
            }
            if(mx > max_len || (mx == max_len&&strncmp(ans, s[0]+i, mx)>0)) {
                strncpy(ans, s[0]+i, mx);
                max_len = mx;
                ans[mx] = '\0';
            }
        }
        if(max_len>0) puts(ans);
        else puts("IDENTITY LOST");
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值