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; }
相关文章推荐
- POJ 3294 Life Forms (后缀数组,求出现在不少于k个字符串的最长子串)
- POJ 3294 Life Forms (后缀数组,求出现在不少于k个字符串的最长子串)
- poj 3294 求多于k个字符串的最长公共子串的个数-------后缀数组+二分答案
- 后缀数组(多个字符串的最长公共子串)—— POJ 3294
- POJ 3415 Life Forms 给定n个字符串,求出现在不小于k个字符串中的最长子串。
- Poj 3294 Life Forms (后缀数组 在n个串中出现k次的最长公共子串并输出)
- POJ 3294 Life Forms 后缀数组+二分 求至少k个字符串中包含的最长子串
- poj 3294 后缀数组求至少在k个串中出现的公共子串
- POJ 题目3294Life Forms(后缀数组求超过k个的串的最长公共子串)
- POJ 3294 后缀数组:求不小于k个字符串中的最长子串
- 【POJ 3294】Life Forms 不小于k个字符串中的最长子串
- POJ 3294 Life Forms(不小于k个字符串中的最长子串 后缀数组)
- POJ 3294 出现在至少K个字符串中的子串
- 字符串hash + 二分答案 - 求最长公共子串 --- poj 2774
- 【poj3294-不小于k个字符串中最长公共子串】后缀数组
- POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串
- 今天开始学Java 查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
- poj 2774 最长公共子串--字符串hash或者后缀数组或者后缀自动机
- poj 3294 Life Forms(n个字符串中 求公共子串长度超过k得最大子串 后缀数组)
- poj 3294 后缀数组 多字符串中不小于 k 个字符串中的最长子串