【编译原理】DFA最小化算法
作者:互联网
【编译原理】DFA最小化算法
DFA的定义
DFA是Determinant Finite Automata,确定性有穷自动机这个定义有几个关键点
-
确定性,Determinant的,也就是说,对于一个串,只有一种可接受方法。(这等价于不存在符号相同的边。)
-
有限,Finite,也就是说节点数量是有限的。
数学地来说:DFA是一个五元组,包括\((S,state,\Sigma,Mov,T)\):初始状态,状态,字符集,状态转移函数,结束状态。
对于OIer的快速入门:一个AC自动机/SAM就是一个DFA,一个\(state\)可以对应成图上的一个节点,\(\Sigma\)就是AC自动机/SAM的字符集,\(S\)就是AC自动机/SAM的开始节点,\(T\)就是接受节点,而\(Mov(A,b)=C\)就是查询\(A\)走一条字符为\(b\)的边到了哪个节点(\(C\)),如果没有这条边那么\((A,b)\)没有不在\(Mov\)函数的定义域。
最小DFA定义
可接受字符串集合相同的DFA称为等价DFA,最小DFA的定义是所有等价DFA中节点最小的,可以证明节点最小的DFA只有一种。
状态(也就是DFA的某个节点)的可区分性
两个点不可区分记为\(A\sim B\)
\(A\sim B\),A和B不可区分当且仅当两个状态的所有出边都对应不可区分。
所有出边对应不可区分当且仅当\(\not \exists c\in \Sigma , Mov(A,c)\not \sim Mov(B,c)\),即符号对应的出边到达的节点不可区分
倍增法求最小化DFA
初始情况,我们能确定,至少所有结束状态和其他节点(非结束状态)是不一样的。
算法的思路是不断寻找可区分的点,并且分裂,层次有点类似B算法求最小生成树。
-
初始情况:\(\prod_0 = S_1,S_2\),\(S_1\)是所有结束状态,\(S_2\)是所有非结束状态
-
迭代方法:假设本次为第\(n\)次迭代。
- 枚举一个\(S_k\in \prod_{n-1}\)
- 枚举所有\(c\in \Sigma\),得到一个集合\(Mov(S_k,c)=\{Mov(X,c):X\in S_k\}\)
- 确认是否每个\(Mov(X,c)\)都有定义(有这条边),都有定义则通过
- 确认是否存在\(S_t\in \prod_{n-1}\),\(Mov(S_k,c)\subseteq S_t\)(所有边都不可区分),存在\(S_t\)则通过
- 若通过以上两种检查,则\(S_k\rightarrow \prod_n\)(加入这个集合)
- 若没有通过以上两种检查,则将\(S_k\)不相交地划分成若干个极大集合\(T_1,T_2\dots T_n\)使得\(\exist S_t\in \prod_{n-1} \textbf{ s.t. } \forall i,Mov(T_i,c)\subseteq S_t\),这里极大集合的意思是\(\forall S_t\in \prod_{n-1}, \not \exist i\not = j \textbf{ s.t. } Mov(T_i,c)\cup Mov(T_j,c) \subseteq S_t\)(将\(S_k\)分裂成若干集合,使得集合内的点的所有出边在\(\prod_{n-1}\)中不可区分,并且希望分裂出的集合数量最小)
使用合适的数据结构可以做到\(O(m \log m)\)
代码到时候再说吧。
这个算法的发明者最终获得了图灵奖!
标签:区分,Mov,编译,集合,最小化,prod,DFA,节点 来源: https://www.cnblogs.com/winlere/p/16115073.html