现在的位置: 首页 > 综合 > 正文

KMP,Extended KMP

2012年05月29日 ⁄ 综合 ⁄ 共 4800字 ⁄ 字号 评论关闭

KMP && Extended KMP:

 

字串a0,a1,a2,a3,a4...an

------------------------------------------------------------------------------

KMP:

记录fail[i]记录假如i+1匹配失败应该退回到哪里。。。

同时也表示了a(i-fail[i]+1)..ai与a0,a1...a(fail[i])匹配。即字串后缀与前缀的匹配。

 

假如fail[10]=5

a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10

a5 a6 a7 a8 a9 a10

 

那么当我们匹配 ci!=a11时 我们就没有必要重新开始只需从a5开始因为

 a5 a6 a7 a8 a9 a10与a1 a2 a3 a4 a5已经匹配

 

 

-------------------------------------------------------------------------------

Extended KMP:

记录一个la[i]长度数组。表示从i开始字串的前缀和字串前缀能够匹配的最大长度。

a0...a(la[i]-1) 与 ai...a(la[i]+i-1) 匹配

做法:

先预处理出la[0]和la[1]; 令 k=1

a0 a1    a2   a3  a4   a5   a6  a7   a8   a9  a10

ck ck+1  ck+2 ck+3 ck+4 ck+5 ck+6ck+7 ck+8 ck+9 ck+10

 

当前做i时,前i-1的la值都是求好的

假设i=ck+t

那么la[i]的计算就可以用上la[i-k]即la[t]的值!!

(显然ck+t..c(xx) 已经和 a(t)..a(xx)匹配了!!!所以la[t]的值就可以用在la[k+t]上!)

假如k的匹配长度为len,而i+la[t]-1仍旧小于len ,那么la[i]就就只能等于la[t];

如果          i+la[t]-1    大于len ,那么就需要继续向下匹配到不能够匹配,

更新k值

----------------------------------------------------------------------------------

两个算法的优化之处都是把之前计算过的有用值记录下来。从而避免重复计算提高效率

-----------------------------------------------------------------------------------

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3298

题目给出模式串A,匹配串B,求A在B中的匹配长度。注意这里的A可以旋转。

1 3 2

2 3 2 1 3 2 1 5

在这里 3 2 1 3 2 1 可以被 1 3 2 匹配。

我们发现到这样一个串一定可以被分成三个部分

3 2 1 3 2 1 5

第一部分 是A串的后缀。第二部分是若干个A串。第三部分是A的前缀。

注意到第一部分同时是自己这个串的后缀。第三部分同时自己这个串的前缀。

注意到上面红字部分。这是我们显然要选择Extended KMP

我们只要对AB做一次Extended KMP。就可以完成第三部分。

将AB串倒过来再做一次Extended KMP。可以完成第一部分。

剩余的就是一遍扫描就可以了。

代码

#include<iostream>
#include
<cstdio>
using namespace std;

int a[1001],b[1000001];
int la[1000001],pl[1000001],pr[1000001];
int n,m,tot,ans,len,l,k,j,t,now;
void swap(int &a,int &b)
{
t
=a;a=b;b=t;
}
int solve()
{

la[0]=n;
j
=0;
while (j<n-1 && a[j+1]==a[j]) ++j;
la[
1]=j;k=1;
for (int i=2;i<n;++i)
{
len
=k+la[k]-1;l=la[i-k];
if (i+l-1<len) la[i]=l;
else
{
j
=0;
if (len-i+1>j) j=len-i+1;
while (i+j<n && a[i+j]==a[j]) ++j;
la[i]
=j;k=i;
}
}

j=0;
while (j<n && j<m && a[j]==b[j]) ++j;
pl[
0]=j;k=0;
for (int i=1;i<m;++i)
{
len
=k+pl[k]-1;l=la[i-k];
if (i+l-1<len) pl[i]=l;
else
{
j
=0;
if (len-i+1>j) j=len-i+1;
while (i+j<m && j<n && b[i+j]==a[j]) ++j;
pl[i]
=j;k=i;
}
}
}
int main()
{
freopen(
"3298.in","r",stdin);
freopen(
"3298.out","w",stdout);
while (cin>>n>>m)
{
ans
=0;
for (int i=0;i<n;++i) scanf("%d",&a[i]);
for (int i=0;i<m;++i) scanf("%d",&b[i]);
solve();
for (int i=0;i<m;++i) pr[i]=pl[i];
for (int i=0;i<n/2;++i) swap(a[i],a[n-i-1]);
for (int i=0;i<m/2;++i) swap(b[i],b[m-i-1]);
solve();

for (int i=0;i<m/2;++i) swap(pl[i],pl[m-1-i]);

for (int i=0;i<m;++i)
{
if ( (i-n<0 || pr[i-n]!=n ) && pr[i]==n)
{
now
=i;
while (now<m && pr[now]==n) now+=n;
tot
=now-i;
if (now<m) tot+=pr[now];
if (i>=1) tot+=pl[i-1];
if (tot>ans) ans=tot;
}
}
if (ans==0) cout<<"bad"<<endl;else

cout<<ans<<endl;
}
return 0;
}

------------------------------------------------------------------------------------

http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1100

表示被2了- -!用cin是自寻死路啊!!!

用scanf读入%lf也是自寻死路!!!

algorithm:

1、将图转化成2*n个特征,边+角度。(很NB的,感觉很难想到!!!)

2、类似上面的方法就可以做出来了。

这数据很2啊,外国人出的数据果断厉害。

我点积算完cos值再acos回去算出0~2*pi的值居然跟距离冲突了,wa一个点。

算完cos值保留下来以0~2的值AC~

数据太强大,scanf读入花了大多数时间。要读int才可能过= =!

--------------------------------------------------------------------------------------

代码

1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4  #define LL long long
5  #define N 1000001
6  #define PI 3.141592653
7 using namespace std;
8 struct node{
9 double x,y;
10 } a[N];
11
12 LL ans,T,n,j,k,L,l;
13 int aa,bb;
14 double b[N],c[N],x1,y11,x2,y2,tt;
15 LL pl[N],pr[N],len[N];
16
17 double dis(node a,node b)
18 {
19 return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) );
20 }
21 double angle(node a,node b,node c)
22 {
23 x1=a.x-b.x;y11=a.y-b.y;x2=c.x-b.x;y2=c.y-b.y;
24 tt=(x1*x2+y11*y2)/dis(a,b)/dis(b,c);
25 if (x1*y2-x2*y11>0) return tt;
26 else return 1+tt;
27 }
28 bool same(double x,double y)
29 {
30 return abs(x-y)<1e-6;
31 }
32 void Ex_Pre_KMP()
33 {
34 len[0]=2*n;
35 j=0;
36 while (j<2*n-1 && same(b[j],b[j+1]) ) ++j;
37 len[1]=j;k=1;
38 for (LL i=2;i<2*n;++i)
39 {
40 L=k+len[k]-1;l=len[i-k];
41 if (i+l-1<L) len[i]=l;
42 else
43 {
44 j=0;
45 if (L-i+1>j) j=L-i+1;
46 while (i+j<2*n && same(b[i+j],b[j]) ) ++j;
47 len[i]=j;k=i;
48 }
49 }
50 }
51 void Ex_KMP()
52 {
53 j=0;
54 while (j<2*n && same(b[j],c[j]) ) ++j;
55 pl[0]=j;k=0;
56 for (LL i=1;i<2*n;++i)
57 {
58 L=k+pl[k]-1;l=len[i-k];
59 if (i+l-1<L) pl[i]=l;
60 else
61 {
62 j=0;
63 if (L-i+1>j) j=L-i+1;
64 while (i+j<2*n && same(c[i+j],b[j]) ) ++j;
65 pl[i]=j;k=i;
66 }
67 }
68 }
69 int main()
70 {
71 freopen("1100.in","r",stdin);
72 freopen("1100.out","w",stdout);
73 cin>>T;
74 for (LL ii=1;ii<=T;++ii)
75 {
76 cin>>n;
77 for (LL i=0;i<n;++i)
78 {
79 scanf("%d %d",&aa,&bb);
80 a[i].x=aa;a[i].y=bb;
81 }
82
83 for (LL i=0;i<n;++i)
84 {
85 b[i*2]=dis(a[i],a[ (i+1) % n ]);
86 b[i*2+1]=angle(a[ i % n],a[(i+1) % n],a[(i+2) % n] );
87 }
88
89 Ex_Pre_KMP();
90 for (LL i=0;i<2*n;++i) c[i]=b[2*n-1-i];
91 Ex_KMP();
92 for (LL i=0;i<2*n;++i) pr[2*n-1-i]=pl[i];
93
94 for (LL i=0;i<n;++i) tt=b[i],b[i]=b[2*n-1-i],b[2*n-1-i]=tt;
95 for (LL i=0;i<n;++i) tt=c[i],c[i]=c[2*n-1-i],c[2*n-1-i]=tt;
96 Ex_Pre_KMP();
97 Ex_KMP();
98
99
100 ans=0;
101 LL lenn;
102 for (LL i=0;i<n;++i)
103 {
104 j=2*i;
105 lenn=j+1;
106 if (pr[j]<lenn/2) continue;
107
108 j=j+1;
109 lenn=2*n-1-j+1;
110 if (pl[j]<lenn/2) continue;
111 ++ans;
112 // cout<<i<<endl;
113 }
114
115 cout<<ans<<endl;
116 }
117 return 0;
118 }
119

抱歉!评论已关闭.