POJ 3450--->Corporate Identity(后缀数组求多个字符串的公共子串)
来源:互联网 发布:软件著作权个人申请 编辑:程序博客网 时间:2024/06/07 12:15
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之后让我们无法判断答案是否存在。
具体请看代码:
#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;}
0 0
- POJ 3450--->Corporate Identity(后缀数组求多个字符串的公共子串)
- POJ 3450 Corporate Identity(kmp求多个字符串的最长公共子串)
- poj 3450 Corporate Identity(后缀数组 多个字符串的最长公共字串)
- Poj 3080 Blue Jeans + Hdu 2328 Corporate Identity (后缀数组 字典序最小的最长公共子串)
- 【后缀数组】 POJ 3450 Corporate Identity
- poj 3450 Corporate Identity (KMP+最长公共子串)
- poj 3450 Corporate Identity 【KMP】【求公共子串】
- poj 3450 Corporate Identity(后缀数组+二分)
- POJ 3450 Corporate Identity(后缀数组+二分)
- POJ-3450 Corporate Identity(KMP/后缀数组)
- POJ 3450 Corporate Identity 求所有字符的最长公共子串
- POJ 3450 Corporate Identity(KMP:最长连续公共子序列)
- POJ 1724 Corporate Identity 后缀数组
- HDU 2328 Corporate Identity(后缀数组-求多个串的最长共同子串)
- POJ3450 Corporate Identity 最长公共子串
- 后缀数组(多个字符串的最长公共子串)—— POJ 3294
- [poj 3450]Corporate Identity[暴力枚举子串]
- 求多个字符串的最大公共子串---后缀数组
- Hust oj 1033 487-3279(map)
- 求最大公约数和最小公倍数
- throw与throws的区别
- 模仿支付宝咻一咻
- 离开易拓网络的第二天,待在图书馆
- POJ 3450--->Corporate Identity(后缀数组求多个字符串的公共子串)
- Solr安装手册
- qt-qml移动开发之在ios上开发和部署app流程简介
- 封装控件的原理
- Border边框
- zend studio项目显示点开头的文件
- 【杭电】[1052]Tian Ji -- The Horse Racing
- HDU 2203亲和串 kmp算法
- Allowance