POJ 3294 Life Forms(后缀数组)
2014-04-19 19:21
225 查看
POJ 3294 Life Forms(后缀数组)
http://poj.org/problem?id=3294
题意:
给你n个字符串,然后要你求出超过一半字符串中的最长公共连续字串是什么,如果有多解,按字典序输出.
分析:
罗穗骞《后缀数组——处理字符串的有力工具》例题.
首先本题依然是连接所有字符串,并且相邻字符串之间用不会出现的不同符号连接.(这里有100个串,如果用char肯定不够用,所以用int表示字符串)
然后对新的字符串求出height数组.现在要二分答案了,判断长为limit的串是否能出现在超过1/2个串中.只需要将height分组,每次取LCP>=limit的一组判断这组内的后缀是不是包括了至少一半的串即可.
AC代码:
http://poj.org/problem?id=3294
题意:
给你n个字符串,然后要你求出超过一半字符串中的最长公共连续字串是什么,如果有多解,按字典序输出.
分析:
罗穗骞《后缀数组——处理字符串的有力工具》例题.
首先本题依然是连接所有字符串,并且相邻字符串之间用不会出现的不同符号连接.(这里有100个串,如果用char肯定不够用,所以用int表示字符串)
然后对新的字符串求出height数组.现在要二分答案了,判断长为limit的串是否能出现在超过1/2个串中.只需要将height分组,每次取LCP>=limit的一组判断这组内的后缀是不是包括了至少一半的串即可.
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100000+1000; int nn;//nn是正好超过所有字符串个数一半的整数 int who[maxn];//who[i]表示后缀i属于原始第几个串,如果为0则是人为添加的字符 int ans[maxn];//ans[i]=x表示第i个答案是串s的后缀x int cnt;//计数答案 int turn=0; struct SuffixArray { int s[maxn]; int sa[maxn],rank[maxn],height[maxn]; int t1[maxn],t2[maxn],c[maxn],n; int vis[maxn];//需要初始化为0,vis[i]=3表示后缀i出现在了第3轮 void build_sa(int m) { int i,*x=t1,*y=t2; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[i]=s[i]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(i=n-k;i<n;i++) y[p++]=i; for(i=0;i<n;i++)if(sa[i]>=k) y[p++]=sa[i]-k; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[y[i]]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1,x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; if(p>=n) break; m=p; } } void build_height() { int i,j,k=0; for(i=0;i<n;i++) rank[sa[i]]=i; for(i=0;i<n;i++) { if(k)k--; j=sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } bool check(int limit) { int i,j,k,t; int ss,flag=0; for(i=2;i<n;i=j+1) { for(;height[i]<limit&&i<n;i++);//i-1是该组下界 for(j=i;height[j]>=limit&&j<n;j++);//j-1是该组上界 if(j-i+1<nn) continue; turn++; //该轮数+1,表示现在是第turn轮 ss=0;//表示该轮小组目前统计到了ss个串的前缀 for(k=i-1;k<j;k++) if( (t=who[sa[k]])!=0 ) if(vis[t]!=turn){ ss++;vis[t]=turn; } if(ss>=nn) if(flag) ans[cnt++]=sa[i-1]; else {cnt=1;ans[0]=sa[i-1];flag=1;} } return flag; } void solve() { memset(vis,0,sizeof(vis)); int min=1,max=n; if(!check(min)) { printf("?\n"); return ; } while(min<=max) { int mid=min+(max-min)/2; if(check(mid))min=mid+1; else max=mid-1; } for(int i=0;i<cnt;i++) { int j=ans[i]; for(int k=0;k<max;k++)printf("%c",s[j+k]-100); printf("\n"); } } }sa; int main() { char str[1000+100]; int n,flag=0; while(scanf("%d",&n)==1&&n) { if(flag==1) printf("\n"); else flag=1; nn=n/2+1;//表示正好>=n/2的那个数 sa.n=0; for(int i=1;i<=n;i++) { scanf("%s",str); int len=strlen(str); for(int j=0;j<len;j++) { sa.s[sa.n+j]=str[j]+100; who[sa.n+j]=i;//归属第几个串 } sa.s[sa.n+len]=i;//分割符 who[sa.n+len]=0;//分割符归属0 sa.n=sa.n+len+1;//串长增加 } sa.s[sa.n-1]=0; sa.build_sa(228); sa.build_height(); sa.solve(); } }
相关文章推荐
- poj3294 Life Forms(后缀数组)
- POJ 3294 Life Forms (后缀数组)
- POJ 3294 Life Forms(后缀数组)
- poj 3294 Life Forms 求n(n>1)个字符串的最长的一个子串 后缀数组
- poj 3294 Life Forms (后缀数组)
- poj 3294 Life Forms(后缀数组)
- POJ 3294 Life Forms (后缀数组)
- poj 3294 Life Forms (后缀数组)
- poj 3294 Life Forms (后缀数组)
- poj 3294 Life Forms (后缀数组应用)
- poj 3294(Life Forms) 2分+ 后缀数组
- POJ 3294 Life Forms(后缀数组)
- POJ 3294 Life Forms(后缀数组)
- poj 3294 Life Forms 后缀数组
- POJ 3294 Life Forms 后缀数组
- POJ3294——Life Forms 后缀数组
- POJ-3294 Life Forms 后缀数组
- poj 3294 后缀数组
- 【后缀数组】【poj 3294】Life Forms
- POJ - 3294 Life Forms