有趣的数学 Puzzle - Sum and Product

前些天在老码农群里看到一个数学 Puzzle,让我联想到另一个红眼睛蓝眼睛的问题,感觉都涉及到一点递归和博弈的意思,仔细思考一下有些趣味,分享给大家。

Sum and Product

随机选择两个数字,都是小于 100 的正整数。Sandy 被告知数字的总和,而 Peter 被告知数字的乘积,假设两个人都是足够理智的情况下,Sandy 和 Peter 之间发生了这个对话:

Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I don't know the numbers.  
Sandy: I don't know the numbers.  
Peter: I do know the numbers.

那么这两个数字是多少?

先自己别看屏幕想个几分钟😏

注意前提是两个人都聪明和理智,知道如何通过目前的情况去推算。

从 1 到 100 两两组合一共有 4590 对数字。Sandy 说我不知道,其实里面隐含着一些信息,因为他知道两个数字之和,所以他说我不知道意味着肯定不是 1 + 1, 1 + 2 … 这种组合,因为这些组合的和在这 4590 对数字中是唯一的。因此 Peter 可以根据 Sandy 的信息排除掉这些组合。

类似的 Peter 每次说我不知道的情况下也可以排除一些组合,依次类推如果经过七轮之后,Peter 说我知道了那个组合,也就有了答案。

通过下面这个 Python 程序更容易理解,源处 Peter And Sandy :

from collections import defaultdict

# build pairs
pairs = []

for i in range(1, 100):
    for j in range(i, 100):
        pairs.append((i, j))

def singles_operation(f):
    results = defaultdict(list)
    for a, b in pairs:
        results[f(a, b)].append((a, b))

    singles = []
    for (k, value) in results.items():
        # We want to return only the product/sum with one result because if
        # peter/sandy have this product/sum, then they'll know the two numbers
        if len(value) == 1:
            singles.extend(value)

    # Sorted for readability
    return sorted(singles, key=lambda x: x[0])


def remove_products():
    singles = singles_operation(lambda x, y: x * y)

    print('peter removed', singles)
    for s in singles:
        pairs.remove(s)

def remove_sums():
    singles = singles_operation(lambda x, y: x + y)

    print('sandy removed', singles)
    for s in singles:
        pairs.remove(s)

for i in range(7):
    remove_products()
    remove_sums()

# This is the result because it returns the only pair with a product
#   not created by anything else left in the list.
print('result', singles_operation(lambda x, y: x * y))

红眼睛、蓝眼睛悖论

此问题最早据说是澳大利亚的华裔数学神童陶哲轩在网上贴出来的:

一个岛上有 100 个人,其中有 5 个红眼睛,95 个蓝眼睛。这个岛有三个奇怪的宗教规则。

  1. 他们不能照镜子,不能看自己眼睛的颜色。
  2. 他们不能告诉别人对方的眼睛是什么颜色。
  3. 一旦有人知道了自己的眼睛颜色,他就必须在当天夜里自杀。

注:虽然题设了有 5 个红眼睛,但岛民是不知道具体数字的。

某天,有个旅行者到了这个岛上。由于不知道这里的规矩,所以他在和全岛人一起狂欢的时候,不留神就说了一句话:你们这里有红眼睛的人。

最后的问题是:假设这个岛上的人足够聪明,每个人都可以做出缜密的逻辑推理。请问这个岛上将会发生什么?

这个问题不简单,这个游客说的话看起来没提供什么新的信息,但却能导致诡异的结果,因为“大家都知道”和“大家知道大家都知道”是不一样的。

Quote

以N=2为例,公开宣告之后,红1立刻获得了一个新的2阶知识:「红2知道岛上有红眼睛」,在公开宣告之前,他没有能力判断这个2阶命题的真假,因为在这之前命题的真假依赖于红1自己的眼睛颜色。同样,红2也获得了新知识「红1知道岛上有红眼睛」。
N=3时,公开宣告使得红1立刻获得了一个新的3阶知识:「红2知道红3知道岛上有红眼睛」,在此之前,这个3阶命题的真假也是依赖于红1自己的眼睛颜色(红则为真,蓝则为假)。同样,红2和红3也获得了类似的知识。N=4,5,6,...依此类推。
简单说,「岛上有红眼睛」这件事本来只是一项「共有知识」(Mutual knowledge),公开宣告使它变成了一项「公共知识」(Common knowledge)。这两种知识的区分在认知逻辑里面非常重要,在博弈论中有广泛的应用。
久而久之,我们越来越习惯于把「你懂的……」挂在嘴边,习惯于对房间里的大象视而不见,选择性遗忘了一个我们其实早就知道的重要事实:「大声说出来」跟「彼此心照不宣」有着决定性的区别。我们不是没有力量。一条恰当的宣言,哪怕它的内容只不过是「我知道」这么简简单单的一句话,也有可能引起整个社会的信念结构的根本改变,让许许多多人断然行动起来。这就是我们每一个人的力量。 ref

李永乐的这个讲解非常好,感谢 SedationH 在评论区推荐给我: