【AC自动机】基于自动机状态设计的动态规划

AC自动机 自动AC机,嗯希望是这样。。。

 

知道了AC自动机的工作原理之后,我不得不发出感慨,这真是个十分漂亮的算法,无论是在时间上还是空间上亦或是常数上,都有非常出色的表现。

AC自动机的基本操作就是多串匹配,最朴素的思想就是跑N边KMP,复杂度是O(NM)的,AC自动机则可以O(M)内岀解。

 

关于AC自动机的介绍,非常感谢这位大牛,他这里讲的非常清楚,AC自动机就是字典树和KMP的结合版本,这里贴出自己的AC自动机的代码:

 

program ACauto; const maxn=250000; var p:array[0..maxn,'a'..'z'] of longint; l,q,c:array[0..maxn] of longint; i,j,k,beg,clo,n,m,t,ans:longint; a,b:ansistring;x:char; begin readln(n,m); readln(a);t:=1; for x:='a' to 'z' do p[0,x]:=1; for i:=1 to n do begin readln(b);k:=1; for j:=1 to length(b) do begin if p[k][b[j]]=0 then begin inc(t);p[k][b[j]]:=t; end; k:=p[k][b[j]]; end; c[k]:=1; end; beg:=1;clo:=1;q[1]:=1; while beg<=clo do begin i:=q[beg]; for x:='a'to'z' do begin t:=l[i]; if p[i][x]=0 then continue; while p[t][x]=0 do t:=l[t]; l[p[i][x]]:=p[t][x]; inc(clo);q[clo]:=p[i][x]; end; inc(beg); end; i:=1;c[0]:=-1; for j:=1 to m do begin while p[i][a[j]]=0 do i:=l[i]; i:=p[i][a[j]];t:=i; while c[t]<>-1 do begin inc(ans,c[t]);c[t]:=-1; t:=l[t]; end; end; writeln(ans); end.

 

 

在网上搜了搜关于AC自动机的题目,找到了这样两道,poj3691,poj2778,很令我神奇的是,他们竟然是动态规划。

 

做了这两道题之后,我发现原来AC自动机也有更多神奇美妙的性质可以挖掘。

先简单描述下3691,给你一些串和一片文章,使得用最少的修改次数使得这篇文章不含有这些串。

DP是大家很快就可以想到的,但是状态压缩是关键,如果用一个进制数来表示状态的话,会远远超过范围。这时我们发现我们并不需要知道主串是个什么样子,只要知道匹配的程度就可以了,AC自动机正好也满足无后效性的性质(匹配状态只和你当前走到那一个点和之后需要匹配的串相关),故我们便可以设计出很漂亮的状态了:

      F[i,j]表示扫描到了第i个字符,在自动机上走到j号节点的最小花费,转移也就很明了了,不改,和改成其他某个字符,限制不能走到匹配成功的点。

poj2778是一道需要矩阵优化的DP,和上题很类似,设计出状态之后便可以构造矩阵DP了,矩阵的复杂度是O(N3),有个优化就是去掉一些冗余状态来减少矩阵乘法的耗时,很明显如果某一个节点是已经匹配成功的节点,那么就可以无视他了。

 

AC自动机应该有更多神奇的功能有待挖掘,嗯。。。。

你可能感兴趣的:(【AC自动机】基于自动机状态设计的动态规划)