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