红眼睛悖论-再解释

之前的分析中可以看出,该问题的关键在于村民如何看待红眼人的存活,因为只有生死状态才是他们判断红眼睛数量信息的唯一依据。

假设 N N N个村民全部都是红眼睛,记为 { x 1 , … , x n } \{x_1,\dots,x_n\} {x1,,xn},很显然这里每个人都能看到 N − 1 N-1 N1双红眼。他们知道自己看到了 N − 1 N-1 N1双红眼,这并不代表他们知道别人也看到了 N − 1 N-1 N1双红眼,因为自己别人自己的状态对别人是未知的。

我们不妨把 { x 1 , … , x n } \{x_1,\dots,x_n\} {x1,,xn}视为一个有 N N N个节点的无向完全图G,其中每个边表示 x i x_i xi知道 x j x_j xj的眼瞳状态。显然 x 1 x_1 x1知道从 x 2 x_2 x2 x n x_n xn的眼瞳颜色,那么对于 x 2 x_2 x2知道多少双眼瞳,这个信息 x 1 x_1 x1知道多少?只要在G中剥掉节点 x 1 x_1 x1 x 2 x_2 x2,由此得到的信息就是 x 1 x_1 x1所掌握的、关于 x 2 x_2 x2观察眼瞳的信息。

x 2 x_2 x2掌握 x 3 x_3 x3观察到多少眼瞳,这一信息也可以通过从G剥夺节点 x 2 x_2 x2 x 3 x_3 x3来发现。而这一信息对于 x 1 x_1 x1掌握多少,只需要再剥夺节点 x 1 x_1 x1就行。

那么,不断重复这一过程,我们很快发现,最后肯定会留下一个节点 x j x_j xj,它被 x i x_i xi推断为没有观察到任何一双红眼瞳

这不是说 x j x_j xj没看到其他红眼瞳: x j x_j xj当然看得到,但这一信息并不被其他人共享

不妨假设 x N x_N xN x 1 x_1 x1推断没有观察到任何红眼瞳。这不是说 x N x_N xN没有观察到从 x 1 x_1 x1 x N − 1 x_{N-1} xN1的红眼瞳,而是说从 x 1 x_1 x1 x N x_N xN的红眼瞳信息并不被 { x 1 , … , x n } \{x_1,\dots,x_n\} {x1,,xn}所有人共享。

实际共享的眼瞳信息为 ∩ i = 1 N { x 1 , … , x n } / { x i } = ∅ \cap_{i=1}^{N}\{x_1,\dots,x_n\} / \{x_i\}=\empty i=1N{x1,,xn}/{xi}=

在旅客宣布有红眼睛存在之前,这一推断被允许成立。

而在旅客宣布之后,这一推断被推翻,这意味着 x 1 x_1 x1知道了 x N x_N xN观察到了从 x 2 x_2 x2 x N − 1 x_{N-1} xN1的任意一双眼瞳。

也就是说实际共享的眼瞳信息为 ∅ ∪ { x j } \empty\cup\{x_j\} {xj},其中每个人对 j j j可取不同值,只要 ∥ ∅ ∪ { x j } ∥ \|\empty\cup\{x_j\}\| ∥∅{xj}相等,即元素数量相等。

于是我们就可以顺理成章地推出:这些村民会选择自杀,当且仅当共享信息的眼瞳数量 ∥ ∅ ∪ { x j } ∥ \|\empty\cup\{x_j\}\| ∥∅{xj}大于自己观察的数量。而这个共享信息在每晚过去之后都会自增 1 1 1——只有他们选择自杀时、这一自增才会停止。

通过软件模拟,可以实现上述流程。以下为Python实现。

import numpy as np
import argparse

def get_watchlist(N,red_eyes):
    watchlist=list()
    for idx in range(N):
        ct=0
        for r in red_eyes:
            if r!=idx:
                ct+=1
        watchlist.append(ct)
    return watchlist

def is_anyone_die(livelist):
    return any(livelist)

def day_passed(livelist,watchlist,selflist):
    for i in range(len(livelist)):
        if livelist[i]==0: # alive
            if watchlist[i]<1:
                if selflist[i]!=0 and (not is_anyone_die(livelist)):
                    selflist[i]=1
                elif is_anyone_die(livelist):
                    selflist[i]=0
            else:
                watchlist[i]-=1

def day_counted(livelist,selflist):
    one_died=False
    for i in range(len(livelist)):
        if livelist[i]==0 and selflist[i]==1:
            livelist[i]=1
            one_died=True
    return one_died

def parse_args():
    parser=argparse.ArgumentParser("Simulator for the red-eye problem")
    parser.add_argument("N",type=int,help="The number of total villages.")
    parser.add_argument("M",type=int,help="Number of red eye persons")
    args=parser.parse_args()
    return args

if __name__=='__main__':
    args=parse_args()
    N,M=args.N,args.M
    if not (M>0 and N>=M):
        print(f"Arguments M={M} and N={N} are not valid! Make sure 0<M<=N!")
    else:
        count_days=M
        red_eyes=np.random.choice(a=N,size=(M,),replace=False).tolist()
        livelist=[0]*N
        watchlist=get_watchlist(N,red_eyes)
        selflist=[-1]*N
        for i in range(count_days):
            day_passed(livelist,watchlist,selflist)
            day_counted(livelist,selflist)
            died=sum(livelist)
            print(f"Day {i+1}: {died} dead.")

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值