这个问题来自 J A H Hunter 写的 Mathematical Brain-Teasers。
有一个部落叫 Kalotan,这里的人有一个很奇怪的特点,那就是男性 从来只说真话;女性从来不会连续说两句真话,也不会连续说两句假 话。
有一天,一个人类学家来到这个部落。遇到一对(异性)夫妇和他们的 小孩 Kibi。人类学家问 Kibi:“你是男孩还是女孩?”
Kibi 说了一句 Kalotan 语。人类学家听不懂,于是转向 Kibi 的父 母询问答案(他们会说英语)。于是其中一个(parent1)对他说: “Kibi 说他是男孩。” 另一个(parent2)对他说:“Kibi 是个女孩。 Kibi 撒谎了。”
请你判断 parent1, parent2 和 Kibi 各自的性别。
如果写一个 Scheme 程序,不但立即就可以解决这个问题。还可以帮 助我们分析这个问题。程序如下:
(define (distinct? . ls) (let loop ((lst (car ls))) (let ((first (car lst)) (rest (cdr lst))) (cond ((null? rest) #t) ((member first rest) #f) (else (loop rest)))))) (define (xor a b) (or (and a (not b)) (and b (not a)))) (define solve-kalotan-puzzle (lambda () (let ((parent1 (amb 'm 'f)) (parent2 (amb 'm 'f)) (kibi (amb 'm 'f)) (kibi-self-desc (amb 'm 'f)) (kibi-lied? (amb #t #f))) ;; Parent1 and parant2 must have distinct sex. (assert (distinct? (list parent1 parent2))) ;; If kibi is a boy, then he will never tell a lie. (assert (if (eqv? kibi 'm) (not kibi-lied?))) (assert (if kibi-lied? (xor (and (eqv? kibi-self-desc 'm) (eqv? kibi 'f)) (and (eqv? kibi-self-desc 'f) (eqv? kibi 'm))))) (assert (if (not kibi-lied?) (xor (and (eqv? kibi-self-desc 'm) (eqv? kibi 'm)) (and (eqv? kibi-self-desc 'f) (eqv? kibi 'f))))) ;; If parent1 is male, ;; parent1 told the truth, ;; parent2 told a truth and a lie, ;; but we don't know which is the truth. (assert (if (eqv? parent1 'm) (and (eqv? kibi-self-desc 'm) (xor (and (eqv? kibi 'f) (eqv? kibi-lied? #f)) (and (eqv? kibi 'm) (eqv? kibi-lied? #t)))))) ;; If parent1 is female, ;; we can't know whether parent1 told the truth, ;; because he(she) said only one sentence, ;; but parent2 must told us all truth. (assert (if (eqv? parent1 'f) (and (eqv? kibi 'f) (eqv? kibi-lied? #t)))) ;; Output the results. (newline) (display "Kibi said its sex is ") (display kibi-self-desc) (display ".\n") (if kibi-lied? (display "Kibi lied.\n") (display "Kibi told the truth.\n")) (display "The sex of parent1, parent2 and Kibi is: ") (display (list parent1 parent2 kibi)) (newline)))) (solve-kalotan-puzzle)
我们用变量 parent1, parent2, kibi 分别表示三个人的 性别。用 kibi-self-desc 表示 Kibi 自称的性别。用 kibi-lied? 表示 Kibi 是否撒谎。
这里有两个帮助函数 distinct? 和 xor。distinct? 可以判断一个 list 里的元素是否没有重复。xor 是异或,当且仅当它只有一个参 数为真时为真。
其它的部分在程序里已经相当明了,不需要多解释了。
执行
(solve-kalotan-puzzle)
就能看到三个人的性别,和对另外一些事实的判断。如果你对这个结 果的唯一性表示怀疑,可以用
(bag-of (solve-kalotan-puzzle))
来看看是不是只有一个答案。