答案假设这些条件,因为任何NFA都可以修改以符合这些要求。
对于任何类型的NFA,您可以添加一个新的初始状态q
0,该状态具有到原始初始状态的epsilon转换,并且还使用称为∅的附加转换符号(他们称之为空集符号,假定为不与原始NFA中的任何符号匹配的符号)从它到任何其他状态,然后使用此新状态作为新的初始状态。请注意,这不会更改原始NFA接受的语言。这将使您的NFA满足第一个条件。
对于任何类型的NFA,您可以添加一个新的接受状态q
a,该状态从原始NFA中的所有接受状态进行epsilon转换。然后将其标记为唯一的接受状态。请注意,这不会更改原始NFA接受的语言。这将使您的NFA满足第二个条件。
通过上述构造,通过设置q
0!= q
a,它满足第三个条件。
在您提供的链接中,第四个条件是通过具有称为∅(空集符号)的特殊转换符号来解释的,其中没有来自原始NFA的实际字母表可以匹配。因此,您可以添加使用此新符号的转换,从每个状态到任何其他状态。请注意,这不会更改原始NFA接受的语言。
因此,现在已修改NFA以满足四个要求,您可以将算法应用于将NFA转换为正则表达式,该正则表达式将接受与原始NFA相同的语言。
编辑以回答进一步问题:
要回答您在评论中的问题,请考虑具有两个状态q
A和q
B的NFA。 q
A是初始状态,也是唯一的接受状态。我们有一个从q
A到自身的符号为0,1的转换。我们还有从q
A到q
B的符号为1的转换。最后,我们有从q
B到q
A的符号为0的转换。
可视化:
0,1
| 1
->qA----->qB
^ |
|-------|
0
第二步。当我们规范化NFA时,只需将新的init状态(q
init)指向q
A,并从q
A添加一个新的接受状态(q
acc)。
第三步。我们希望删除q
A。因此,q
A是算法中的q
rip(在第3页)。现在我们需要考虑进入q
A的每个状态和从q
A出去的每个状态。在这种情况下,有两个指向q
A的状态,即q
init和q
B。有两个被q
A指向的状态,即q
B和q
acc。根据算法,我们用过渡符号R
dir+R
in(R
rip)*R
out替换过渡q
in->q
rip->q
out,其中:
- Rdir是从qin到qout的原始转换
- Rin是从qin到qrip的原始转换
- Rrip是qrip处的原始循环
- Rout是从qrip到qout的原始转换
因此,在这种情况下,我们用过渡符号(0+1)*1将过渡qinit->qA->qB替换为qinit->qB。继续这个过程,我们总共会创建4个新的转换:
- qinit->qB:(0+1)*1
- qinit->qacc:(0+1)*
- qB->qB:0(0+1)*1
- qB->qacc:0(0+1)*
然后我们可以删除qA。
第四步。我们希望删除qB。同样,我们确定qin和qout。这里只有一个状态进入qB,即qinit,只有一个状态离开qB,即qacc。因此,我们有:
- Rdir = (0+1)*
- Rin = (0+1)*1
- Rrip = 0(0+1)*1
- Rout = 0(0+1)*
因此,新的转换 qinit->qacc 将为:
Rdir+Rin(Rrip)*Rout
(0+1)* + (0+1)*1 (0(0+1)*1)* 0(0+1)*
我们可以删除 qB。
第五步。由于原始 NFA 中的每个状态都已被删除,因此我们完成了。因此,上述是最终的正则表达式。
请注意,最终的正则表达式可能不是最优的(在大多数情况下,它不会是最优的),这是该算法所预期的。通常很难找到 NFA(甚至是 DFA)的最短正则表达式(尽管对于本例来说,很容易看出第一个组件已经涵盖了所有可能的字符串)
为了完整起见,接受相同语言的最短正则表达式将是:
(0+1)*