您的位置:首页 > 其它

poj 3294 在K个字符串中出现最长公共子串

2013-02-05 13:57 441 查看
后缀数组二分长度判定,然后将height数组通过二分得到长度分成几部分,检查每一部分是否有超过半数的字符串出现当前长度的公共子串。然后保存位置信息用于输出。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int nMax=101005;
int pos[nMax],cnt,flag[105],cnt1,hash[nMax];
int r[nMax],N;
int sa[nMax], rank[nMax], height[nMax];
int wa[nMax], wb[nMax], wv[nMax], wd[nMax];

int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}

void da(int *r, int n, int m)
{          //  倍增算法 r为待匹配数组  n为总长度(包含结尾的0) m为字符范围
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p)
{
for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
for(i = 0; i < n; i ++) wv[i] = x[y[i]];
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)
{
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
}
}
}

void calHeight(int *r, int n){           //  求height数组。
int i, j, k = 0;
for(i = 1; i <= n; i ++) rank[sa[i]] = i; // 1->n
for(i = 0; i < n; i++){
for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
height[rank[i]] = k;
}
}
int ok(int lim,int n)
{
int cnt_tmp=0;
for(int i=2;i<=n;i++)
{
if(height[i]<lim)
{
if(cnt1>N/2)
pos[cnt_tmp++]=sa[i-1];
memset(flag,0,sizeof(flag));
cnt1=0;
}
else
{
int a=sa[i],b=sa[i-1];
if(!flag[hash[a]] && hash[a]<N)
{
flag[hash[a]]=1;cnt1++;
}
if(!flag[hash[b]] && hash[b]<N)
{
flag[hash[b]]=1; cnt1++;
}
}
}
if(cnt_tmp>0)
{
cnt=cnt_tmp;
return 1;
}
return 0;
}
int main()
{
//   freopen("test.txt","r",stdin);
char s[nMax];
while(scanf("%d",&N) && N)
{
int n=0,pn=0;
for(int i=0;i<N;i++)
{
scanf("%s",s+pn);
n=strlen(s+pn);
for(int j=pn;j<pn+n;j++)
hash[j]=i;
if(i==N-1) break;
s[pn+n]='#';
hash[pn+n]=i+N;
pn=pn+n+1;
}
n=strlen(s);int cnt_tmp=28;
for(int i=0;i<n;i++)
{
if(s[i]!='#')
r[i]=s[i]-'a'+1;
else r[i]=cnt_tmp++;
}
r
=0;
da(r,n+1,N+27);
calHeight(r,n);

int l=0,r=1000,mid,ret=0;
memset(flag,0,sizeof(flag));
while(l<=r)
{
mid=(l+r)>>1;
if(ok(mid,n))
{
ret=mid;
l=mid+1;
}
else r=mid-1;
}

if(ret==0)
{
printf("?\n\n");
continue;
}
for(int i=0;i<cnt;i++)
{
for(int j=pos[i];j<pos[i]+ret;j++)
printf("%c",s[j]);
printf("\n");
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐