从字母{a,b,c}构建DFA的最佳方法是什么?

时间:2017-10-09 19:44:30

标签: computer-science automata finite-automata nfa

我试图在字母{a,b,c}上建立一个DFA,接受所有字符串的连续三个字母。

所以例如它可以接受:aaa,bbb,ccc,abbb,caaac,ccbbbcc,aaabbbc ..

我尝试了不同的方法,但它变成了一个巨大的图表我想知道是否有更优雅的方式来做这个?

1 个答案:

答案 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-/

我们的州执行以下操作:

  • q0:初始状态接受任何前缀,包括' s和c&#39>。
  • q1,q4:只能通过带有aa作为子字符串的字符串访问的状态
  • q2,q5:只能通过bb作为子字符串的字符串访问的状态
  • q3,q6:只能通过cc作为子字符串的字符串访问的状态
  • q7:只接受带有aaa,bbb或ccc作为子字符串的字符串访问的接受状态。

在读取输入字符串的一些前缀后,NFA不确定地分支以检查输入字符串是否包含aaa,bbb或ccc,如果是,则输入q7并接受可能保留的后缀。

要获得DFA,确实是最小的DFA,我建议按照Myhill-Nerode定理进行检查,按字典顺序检查字符串,看看它们是否与我们已经考虑过的字符串有区别,因此设计我们的DFA状态为时间。

  1. 空字符串是可区分的。它可以跟随L中的任何字符串以获取L中的字符串。调用其状态[e]。
  2. 字符串a可以与空字符串区分开来,因为它可以跟随aaL + L来获取L中的字符串。调用它的状态[a]。
  3. 字符串b和c同样可以区分,并且具有状态[b]和[c]。
  4. 字符串[aa]是可区分的,因为它可以跟随aL + L来获取L中的字符串。调用其状态[aa]。
  5. 字符串bb和cc同样可以区分,并且具有状态[bb]和[cc]。
  6. ba和ca与a无法区分;它们后跟与a相同的字符串,以获取L中的字符串。
  7. ab / cb和ac / bc分别与b和c无法区分。
  8. aaa是可以区分的,因为它可以跟随任何东西,它仍然是该语言的字符串。
  9. bbb和ccc与aaa无法区分。
  10. 长度为3的所有其他字符串与a,b,c,aa,bb或cc无法区分(查看此内容)
  11. 所有以aaa开头的长度为4的字符串与较短的字符串无法区分(请查看此内容)
  12. 因为我们用尽了可辨别的字符串,我们知道我们列出了最小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具有相同数量的状态 - 这恰好会消除非确定性。

    • 我们获得转换的方式是通过查看符号s上的状态[x]到状态[y]来查看xs是否与z无法区分。
    • 我们获得初始状态的方式是它总是[e]。
    • 我们获得接受状态的方式是它是唯一可以遵循其字符串的人,以获得L中的字符串。