【BZOJ 2946】 2946: [Poi2000]公共串 (SAM)

2946: [Poi2000]公共串

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1063  Solved: 469

Description

       给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:
l        读入单词
l        计算最长公共子串的长度
l        输出结果

Input

文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

Output

仅一行,一个整数,最长公共子串的长度。

Sample Input

3
abcb
bca
acbc

Sample Output

HINT

Source

 

 

【分析】

  重新学一次SAM,从刷水题开始。

  同spoj1812。用第一个串建sam,然后用其他的串跑,ans存在那个点那里,做完一个串的时候还要根据parent边的拓扑序更新该点ans,最后取min即可。

  当然后缀数组也是可以的。

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 2010
 8 
 9 int mymax(int x,int y) {return x>y?x:y;}
10 int mymin(int x,int y) {return x<y?x:y;}
11 
12 struct node
13 {
14     int pre,son[30],step;
15     // node() {pre=step=0;memset(son,0,sizeof(son));}
16 }t[Maxn*2];
17 int ans[Maxn*2],ad[Maxn*2];
18 
19 struct sam
20 {
21     int last,tot;
22     /*void upd(int x)
23     {
24         memset(t[x].son,0,sizeof(t[x].son));
25     }*/
26     void extend(int k)
27     {
28         int np=++tot,p=last;
29         t[np].step=t[last].step+1;
30         while(p&&!t[p].son[k])
31         {
32             t[p].son[k]=np;
33             p=t[p].pre;
34         }
35         if(!p) t[np].pre=1;
36         else
37         {
38             int q=t[p].son[k];
39             if(t[q].step==t[p].step+1) t[np].pre=q;
40             else
41             {
42                 int nq=++tot;//upd(tot);
43                 t[nq].step=t[p].step+1;
44                 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
45                 t[nq].pre=t[q].pre;
46                 t[q].pre=t[np].pre=nq;
47                 while(p&&t[p].son[k]==q)
48                 {
49                     t[p].son[k]=nq;
50                     p=t[p].pre;
51                 }
52             }
53         }
54         last=np;
55     }
56     
57 }sam;
58 
59 char s[10],ss[Maxn];
60 
61 int main()
62 {
63     int n;scanf("%d",&n);
64     scanf("%s",s);
65     sam.last=sam.tot=1;
66     int l=strlen(s);
67     for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1);
68     memset(ans,63,sizeof(ans));
69     for(int i=2;i<=n;i++)
70     {
71         scanf("%s",s);
72         l=strlen(s);
73         int nw=1,sp=0;
74         for(int j=1;j<=sam.tot;j++) ad[j]=0;
75         for(int j=0;j<l;j++)
76         {
77             int ind=s[j]-'a'+1;
78             while(nw&&!t[nw].son[ind]) nw=t[nw].pre,sp=t[nw].step;
79             if(t[nw].son[ind]) sp++,nw=t[nw].son[ind];
80             else nw=1,sp=0;
81             ad[nw]=mymax(ad[nw],sp);
82         }
83         for(int i=sam.tot;i>=1;i--) ad[t[i].pre]=mymax(ad[t[i].pre],mymin(ad[i],t[t[i].pre].step));
84         for(int i=sam.tot;i>=1;i--) ans[i]=mymin(ans[i],ad[i]);
85     }
86     int mx=0;
87     for(int i=1;i<=sam.tot;i++) if(ans[i]<=sam.tot) mx=mymax(mx,ans[i]);
88     printf("%d\n",mx);
89     return 0;
90 }
View Code

 

2017-04-17 10:21:42

posted @ 2017-04-17 10:21  konjak魔芋  阅读(158)  评论(0编辑  收藏  举报