POJ 3450--->Corporate Identity(后缀数组求多个字符串的公共子串)
2016-07-23 18:10
651 查看
http://poj.org/problem?id=3450
这题大概就是给你一堆字符串找到这堆字符串的公共部分
这题标准答案是kmp,我有一篇用KMP做的–》http://blog.csdn.net/my_stage/article/details/52004770
必须感叹一下,即使有后缀数组这样的数据结构但在这道题上依然还是比不过Kmp算法,同样这题也是后缀数组的一个模板题,希望大家可以有所收获,
首先这题很其他模板题一样,先是把所以字符串连接,之后每个字符串中间用一个从未出现的字符分隔,比如这题中我把所以的小写转换成数字,那么我所用的分隔数是30,那么每次输入一个新的字符都会让这个分隔数加1,这样便于我们构建后缀数组,并且我们用一个数组标记输入字符串的序号。这是为了之后的操作做的准备。
之后通过2倍倍增算法(也就是那边传说中的论文里的模板算法)求出sa,rank,height数组。
之后我们将答案二分,记住 left=1,right=len(len为最后一个字符串的长度) 之后开始二分,记住不要让left=0,因为这样最后会得到mid=0之后让我们无法判断答案是否存在。
具体请看代码:
这题大概就是给你一堆字符串找到这堆字符串的公共部分
这题标准答案是kmp,我有一篇用KMP做的–》http://blog.csdn.net/my_stage/article/details/52004770
必须感叹一下,即使有后缀数组这样的数据结构但在这道题上依然还是比不过Kmp算法,同样这题也是后缀数组的一个模板题,希望大家可以有所收获,
首先这题很其他模板题一样,先是把所以字符串连接,之后每个字符串中间用一个从未出现的字符分隔,比如这题中我把所以的小写转换成数字,那么我所用的分隔数是30,那么每次输入一个新的字符都会让这个分隔数加1,这样便于我们构建后缀数组,并且我们用一个数组标记输入字符串的序号。这是为了之后的操作做的准备。
之后通过2倍倍增算法(也就是那边传说中的论文里的模板算法)求出sa,rank,height数组。
之后我们将答案二分,记住 left=1,right=len(len为最后一个字符串的长度) 之后开始二分,记住不要让left=0,因为这样最后会得到mid=0之后让我们无法判断答案是否存在。
具体请看代码:
#include <stdio.h> #include <algorithm> #include <string.h> #define maxs 1000005 #include <iostream> using namespace std; #define MME(i,j) memset(i,j,sizeof(i)) int s[maxs],sa[maxs],rank[maxs],height[maxs]; int wa[maxs],loc[maxs],wb[maxs],wv[maxs],wd[maxs]; char input[205]; int ans; int cmp(int *r,int a,int b,int L) { return r[a]==r[b]&&r[a+L]==r[b+L]; } void get_sa(int *r,int n,int m) { int i,j,p,*x=wa,*y=wb; 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(swap(x,y),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++; } } /* for(int i=0;i<n;i++) printf("SA[%d] is %d\n",i,sa[i]); */} void build_height(int *r,int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]= i; for(i=0;i<n;height[rank[i++]]=k){ for(k ? k-- : 0, j=sa[rank[i]-1]; r[i+k] == r[j+k] ; k++); } /* for(int i=0;i<=n;i++) printf("h[%d] is %d\n",i,height[i]); */} bool vis[4010]; char ans_str[maxs]; bool check(int mid,int len,int appear) { MME(vis,0);//len 为 s 数组 的长度 int i,j,tmp=0; for(i=2;i<len;i++) { if(height[i]<mid) { tmp=0; MME(vis,0); continue; } if(!vis[loc[sa[i-1]]]) { tmp++; vis[loc[sa[i-1]]]=1; } if(!vis[loc[sa[i]]]) { tmp++; vis[loc[sa[i]]]=1; } if(tmp==appear) { //printf("MId is %d I is %d\n",mid,i); for(j=0;j<mid;j++) { ans_str[j]=s[sa[i]+j]+'a'-2; } // ans_str[mid]='\0'; return true; } //printf("MID is %d\n",mid); ans_str[mid]='\0'; } return 0; } int main() { int cnt,n,len; while(~scanf("%d",&n)&&n) { ans=0; cnt=0; int j,id,temp=30; for(int i=0;i<n;i++) { // memset(input,'\0',sizeof(input)); scanf("%s",input); len=strlen(input); for(j=0;j<len;j++) { id = input[j]-'a'+2; loc[cnt] = i; // 把字符串分组 s[cnt++] = id; } loc[cnt] =temp; s[cnt++] =temp++; } s[cnt]=0; get_sa(s,cnt+1,temp); build_height(s,cnt); int left=1,right=len,mid; bool flag=0; while(left<=right) { mid=(left+right)/2; if(check(mid,cnt,n)) { flag=1; left=mid+1; // ans=mid; } else right=mid-1; } if(flag) puts(ans_str); else printf("IDENTITY LOST\n"); } return 0; }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#数据结构之顺序表(SeqList)实例详解
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- Lua教程(七):数据结构详解
- C#算法函数:获取一个字符串中的最大长度的数字
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码