针对语言为{a,b}的语法进行构建
{a^m b^n | 0 <= n <= m <= 3n}
我不确定该怎么解决,我从做起就开始
n >= 0
m >= n
3n >= m
S -> a S b | a S bb
答案 0 :(得分:1)
那非常接近。有几个问题:
您需要一个基本案例。由于 n 可以为零,因此ε(空字符串)位于语言中。这样就可以告诉您从哪里开始。
您似乎认为b
比a
多。但是b
s( n )的数目小于或等于a
s( m )的数目。不能再有b
个。无需为每个b
添加一个或两个a
,而是需要为每个a
添加一个或两个b
。 (但请参见下文。)
您仅处理将一个额外的a
与一个或两个b
配对的情况,如上所述,应该颠倒它们,以便将另外的b
配对和一些a
。但是语言描述是 m ≤3* n *,而不是 m ≤2* n *;额外的b
可以与最多三个a
配对。
答案 1 :(得分:1)
我发现从语言中最短的字符串开始,然后尝试从那里进行概括是很有帮助的。该语言中最短的字符串是什么?我们可以选择n = 0和m = 0,因为0 <= 0 <= 0 <= 3x0,所以空字符串在我们的语言中。因为空字符串是语言中的语言,所以我们必须在语法中产生一个S := e
这样的产生式。
现在,我们如何获得更长的语言字符串?我们可以添加一些产品,仅用于在字符串中添加a或仅添加b;但是,此类规则不能用于扩展基本情况(S := e
),因为在空字符串中添加仅或仅b不会获得该语言的字符串。这些产品可能会使我们陷入语言障碍,但它们不会以明显或简单的方式使我们走上这样的道路。我们希望语法简单,因此我们可以确信它是正确的。
分别添加a和b的替代方法是将它们添加在一起。请注意,当您使用的语言中,字符串的各个部分相互依赖时,通常(总是,除非有明显的依赖关系而不是实际的依赖关系,除非如此)会发现生成必须与那些依赖的部分相关联;否则,在派生字符串期间可能会“忘记”依赖项。我们假设我们的产品应该只将a和b加在一起,然后继续该假设。
首先,我们可能猜测语法S := aSb
应该包含在语法中。为什么我们会猜测呢?好吧,基于我们的假设,我们知道我们需要将a和b加在一起,我们在这里要做。另外,由于我们希望规则产生一般长度的字符串,因此我们了解到,产生必须涉及一个非终结符,而目前我们只有一个非终结符(还记得我们正在努力在基本情况下构建字符串,由S
产生;因此使用此非终结符是自然的)。最后,我们知道所有a必须在所有b的左侧,这是根据该模式生成字符串的三个符号的唯一顺序。
此作品允许我们生成哪些字符串?我们可以得到S := e
,S := aSb := ab
,S := aSb := aaSbb := aabb
,…,S := … := (a^n)(b^n)
。我们观察到这些字符串是用语言表示的-因为0 <= n <= n <= 3n-但是该生成本身会丢失一些字符串。在这种情况下,生产状况良好,应予以保留;但是,我们错过了一些字符串,这表明我们需要找到其他作品来弥补这些情况。
我们错过了哪些案例?我们错过了m严格大于n的情况。我们猜想在生产中,我们使用了相同的数字a和b,因此最终得到了具有相同数字的字符串。可以肯定地说,如果我们想要a大于b的字符串,那么我们就需要具有引入a大于b的形式。根据我们的假设,我们仍然要求我们至少引入两者之一。并且我们已经介绍了其中一种。下一个要猜测的逻辑产物是S := aaSb
。我们现在可以生成什么字符串?如果我们忽略了生产S := aSb
,则新的生产使我们能够以我们的语言生成字符串形式为(a^2n)(b^n)
的字符串。但是当我们考虑所有三个作品时会发生什么?
考虑字符串(a^k)(b^n)
,其中n <= k <= 2n。如果k = n,那么我们可以使用S := aSb
的乘积n次来获取字符串。同样,如果k = 2n
,我们可以使用生产S := aaSb
n次。如果n < k < 2n
怎么办?假设k = n + j,其中0 S := aSb
恰好使用n - j
次,以获得2j + n - j = n + j = k
实例a和b的n个实例。因此,这三个规则使我们能够生成所有字符串,其中a的数量在b的数量和b的数量的两倍之间(包括两端)。
我们仍然无法生成a的数量大于b的两倍的字符串;但是,根据我们的上述成功经验,我们可以猜测S := aaaSb
并使用类似的推理来证明这四个产品共同为我们提供了我们要生成的语言。我们得出的语法如下:
S := e
S := aSb
S := aaSb
S := aaaSb
该语言还有许多其他语法,所有语法都正确,并且许多语法是使用完全不同于此的方法得出的。不要将此类问题视为应用公式来获取预定答案的问题。将这样的问题想成是什么:编程问题。您已获得规格,只要您的产品有效,那便很重要。