你有4个条件要同时满足,
让我们将条件称为 P、Q、R 和 S
-
P:接受的字符串必须至少 5 个字符长
-
Q:接受的字符串必须包含至少一个小写字母
-
R:接受的字符串必须包含至少一个大写字母
-
S:接受的字符串,它们必须包含至少一位数字。
无论其他条件如何,每个条件都可以为真或假。
如果我们用 1 表示 true,用 0 表示 false,我们得到 16
distinct 不同的可能性,我们可以用一个事实来形象化
表格(为便于阅读而分组):
P | Q | R | S
---------------
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
让我们用q[0, 0, 0, 0] 表示第一行,第二行用q[0,
0, 0, 1] 表示,依此类推。我们不会真正使用所有的状态,特别是
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
将保持未使用状态。然而,我们将需要一个额外的状态,即
在真值表中没有语义等价物。我们会打电话
这个状态Foo。稍后会详细介绍。
现在我们必须指定每个转换
状态,以及识别我们的初始状态。
对于每个状态,必须描述每个输入字符的转换。
让我们采用这样的符号
q[0, 0, 0, 0] ---ABC--> q[0, 0, 1, 0]
表示当我们处于q[0, 0, 0, 0] 状态并且我们阅读任何
字符A、B或C我们执行上述状态转换。
现在,我将只展示最终 DFA 的一部分,因为我们可以编写
解决方案的其余部分使用它作为模板。
q[0, 0, 0, 0] 是我们的初始状态,对于输入“ABC”,我们得到
q[0, 0, 0, 0] ---ABC--> q[0, 0, 1, 0]
我们现在读到了一个大写字母。从这里有三种可能,
我们读取另一个大写字母并保持相同的状态:
q[0, 0, 1, 0] ---ABC--> q[0, 0, 1, 0]
或者我们读取一组数字或一组小写字母:
q[0, 0, 1, 0] ---012--> q[0, 0, 1, 1]
q[0, 0, 1, 0] ---abc--> q[0, 1, 1, 0]
然后,对于任一状态,我们都可以继续消耗所有输入
到目前为止,我们遇到过,即。那个
q[0, 0, 1, 1] --ABC012--> q[0, 0, 1, 1]
和
q[0, 1, 1, 0] --ABCabc--> q[0, 1, 1, 0]
现在,如果我们处于q[0, 0, 1, 1] 状态并读取一个小写字母
我们到达状态q[0, 1, 1, 1],如果我们在状态类似
q[0, 1, 1, 0] 并读取我们以 q[0, 1, 1, 1] 结尾的数字。在这
点我们已经阅读了 3 个或更多字符!
现在,从
q[0, 1, 1, 1]
在达到接受状态之前,我们需要读取两个字符。
在这里,我将使用“X”来表示“随便,只要它是一个字符
来自集合 {0, 1, 2, a, b, c, A, B, C}"。
所以,从q[0, 1, 1, 1] 我们得到以下转换序列
q[0, 1, 1, 1] -- X --> Foo -- X --> q[1, 1, 1, 1]
当我们在q[1, 1, 1, 1] 时,我们就有了
q[1, 1, 1, 1] -- X --> q[1, 1, 1, 1]
我们可以像这样设想所有这些过渡(我决定省略
在这一点上使用逗号来降低设备上的换行风险
小屏幕),
ABCabc loops back here
|
V
+--abc--> q[0110] --012--+
| |
| V
q[0000] --ABC--> q[0010] --+ q[0111]-- X -- Foo -- X --> q[1111]
| ^ | ^
| | | |
+-ABC-+ +--012--> q[0011] --abc--+
^
|
ABC012 loops back here
如果我们从 012 开始,我们就会有
012abc loops back here
|
V
+--abc--> q[0101] --ABC--+
| |
| V
q[0000] --012--> q[0001] --+ q[0111]-- X -- Foo -- X --> q[1111]
| ^ | ^
| | | |
+-012-+ +--ABC--> q[0011] --abc--+
^
|
ABC012 loops back here
所以存在对称性,我们可以为
当第一个构造是“abc”时。这就是饼干的方式
崩溃。