我试图在字母{a,b,c}上建立一个DFA,接受所有字符串的连续三个字母。
所以例如它可以接受:aaa,bbb,ccc,abbb,caaac,ccbbbcc,aaabbbc ..
我尝试了不同的方法,但它变成了一个巨大的图表我想知道是否有更优雅的方式来做这个?
答案 0 :(得分:2)
首先,你的标题是NFA,但你问题的主体说DFA。我会回答两种方式来说明为什么重要。
首先考虑NFA。我们只想接受具有三个相同类型的连续符号的字符串。有三个符号,因此有三种方式可以发生(假设我们认识到字符串将在第一次出现三个连续符号后被接受)。我们可以看到任何东西,然后是三个相同的符号,然后再看到任何东西。 NFA很容易写下来:
__
/ \ __
| / a,b,c / \
V / | / a,b,c
--->q0--a->q1-a->q4-a-\ V /
| \-b->q2-b->q5-b-->(q7)
\---c->q3-c->q6-c-/
我们的州执行以下操作:
在读取输入字符串的一些前缀后,NFA不确定地分支以检查输入字符串是否包含aaa,bbb或ccc,如果是,则输入q7并接受可能保留的后缀。
要获得DFA,确实是最小的DFA,我建议按照Myhill-Nerode定理进行检查,按字典顺序检查字符串,看看它们是否与我们已经考虑过的字符串有区别,因此设计我们的DFA状态为时间。
因为我们用尽了可辨别的字符串,我们知道我们列出了最小DFA的所有必要状态,我们可以写下答案:
+---a--->[a]<---a----+
| +-c--->[c]<---c-+ |
| | | |
+----b--->[b]-------b------>[bb]---b----+
| |
| +---b--->[b]<---b----+ | +--+
| | +-c--->[c]<---c-+ | | | a,b,c
| | | | | V V |
--->[e]---a--->[a]-------a------>[aa]---a--->[aaa]--+
| ^
| +---a--->[a]<---a----+ |
| | +-b--->[b]<---b-+ | |
| | | | | |
+----c--->[c]-------c------>[cc]---c----+
(状态[a],[b]和[c]每次重复两次,以使图表更漂亮。实际上,状态转换图形不是平面的,渲染会很混乱完全没有,更不用说ASCII艺术了。)
请注意,这与我们记下的简单NFA具有相同数量的状态 - 这恰好会消除非确定性。