您的位置:首页 > 其它

SPOJ LCS2 多个串的最长公共子串

2015-06-19 02:01 417 查看
这里串最多有10个,找所有串的最长公共子串

这里后缀自动机做,以第一个串建立后缀自动机,后面的串一个个去匹配,每次得到当前串在可到达状态上所能得到的最长后缀长度

拿所有串匹配后得到的结果进行计算

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define M 26
#define N 200100
char str
;
struct SamNode{
SamNode *son[M] , *f;
int l , nc , c;
}sam
, *last , *root , *b
;

int cnt , num
;

void init()
{
root = last = &sam[cnt=0];
}

void add(int x)
{
SamNode *p = &sam[++cnt] , *jp=last;
p->l = jp->l+1 , p->nc = p->l;
last = p;
for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p;
if(!jp) p->f = root;
else{
if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
else{
SamNode *r = &sam[++cnt] , *q = jp->son[x];
*r = *q;
r->l = r->nc = jp->l+1;
q->f = p->f = r;
for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
}

void solve()
{
int len = strlen(str) , ret;
for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
while(~scanf("%s" , str)){
len = strlen(str) , ret=0;
SamNode *cur = root;
for(int i=0 ; i<len ; i++){
int x = str[i]-'a';
if(cur->son[x]){
ret++;
cur = cur->son[x];
}
else{
while(cur && !cur->son[x]) cur = cur->f;
if(!cur){
cur = root;
ret = 0;
}else{
ret = cur->l+1;
cur = cur->son[x];
}
}
cur->c = max(cur->c , ret);
}
for(int i=cnt ; i>0 ; i--){
b[i]->nc = min(b[i]->nc , b[i]->c);
//子节点可接受到的后缀父节点必定能够接收到,反之却不一定
b[i]->f->c = max(b[i]->f->c , b[i]->c);
b[i]->c = 0;
}
}
}

int main() {
//    freopen("a.in" , "r" , stdin);
scanf("%s" , str);
init();
int len = (int)strlen(str);
for(int i=0 ; i<len ; i++) add(str[i]-'a');
solve();
int ret = 0;
SamNode *cur;
for(int i=1 ; i<=cnt ; i++){
cur = &sam[i];
ret = max(cur->nc , ret);
}
printf("%d\n" , ret);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: