密码学的应用范围非常广泛。每一样简单的社交活动里都有很大的学问。考虑这样一个问题,两个人想通过一部电话打牌,但他们都不信任对方。有没有可能仅通过一部电话实现扑克牌协议,并且保证游戏的公正性呢?
扑克牌的信息隐蔽性带来了很多与密码学协议相关的有趣问题。两个象棋大师可以在洗澡间一边冲澡一边大喊“炮八平五”、“马八进七”,一对围棋情侣可以在床上一边亲热一边呻吟“点三三”、“拆二”。等事情办完了,一盘精彩的棋局或许也就结束了。这些棋类游戏之所以可以“盲下”,就是因为在棋类游戏中,双方的局面信息都是完全公开的。不过,打牌就是另外一码事了。你说你出方片7,我怎么知道你有一个方片7?事先发牌?那谁来负责发牌呢?怎样发牌呢?难道我告诉你“发到你手中的是两张3一张5一张8一张9”?这样一看,两个人“盲打扑克牌”似乎是不可能的了,要么需要借助道具,要么需要第三者的帮助。不过,运用密码学知识,我们可以设计一套扑克牌协议,该协议能够实现随机的、隐蔽的、公平的发牌,并且不需要其它东西的帮助。我们以一手五张牌为例,说明如何实现“两人各摸五张牌”的程序。
趣题
经典证明:Chaitin定理 不可能编程判断代码的最简性
今天学到一个好玩的东西。仿照停机问题的研究方法,我们可以想出很多有趣的不可解问题。Gregory Chaitin曾经提出过下面这个问题。如果两段代码运行之后能够输出相同的结果,我们就称较短的代码比长一点的那个更简洁(注意,如果程序需要读入数据,读入的数据也算进代码长度)。对于一个指定的输出,一定存在一个“最简的”代码,它是所有能输出此内容的程序代码中最短的一个。在刚刚结束的TLE比赛中,参数选手拼了命地缩减每一个字符,写出来的代码一个比一个短。有人或许在想,这些代码究竟能短到什么程度?你如何才能知道你的代码已经不再有改进的空间了?受此启发,我们的问题出来了:你能否编写一个程序,使得该程序能够判断任意一段代码是否是最简的?
Chaitin定理指出,上述问题是一个不可解问题,再牛的人也不可能编写出这样的程序。证明方式与大多数此类问题一样,都是采用反证加构造的方法证明的。你能想到这个证明方法吗?
拥有多个A的概率:又一个条件概率悖论
概率论给我们带来了很多匪夷所思的反常结果,条件概率尤其如此。网络上每一次有人发帖提出与条件概率有关的悖论时,总会引来无数人的围观和争论,哪怕这些问题的实质都是相同的。
来看两道简单的组合数学问题:
1. 四个人打桥牌。其中一个人说,我手上有一个A。请问他手上有不止一个A的概率是多少?
2. 四个人打桥牌。其中一个人说,我手上有一个黑桃A。请问他手上有不止一个A的概率是多少?
这两个问题看起来很像,实际算法大不相同。在第一题问题中,
手上一个A也没有 有 C(48,13) 种情况
手上有至少一个A 有 C(52,13) – C(48,13) 种情况
手上恰好有一个A 有 C(48,12) * 4 种情况
手上有至少两个A 有 C(52,13) – C(48,13) – C(48,12) * 4 种情况
根据条件概率公式,手上有超过一个A的概率为(C(52,13) – C(48,13) – C(48,12) * 4) / (C(52,13) – C(48,13)) = 5359/14498 ≈ 37%
趣题:在双向有序链表中查找指定的数
大家都知道,在一个有序数组里查找指定的数可以做到O(logn)的复杂度。但是大家想过没,在一个有序链表中又怎么样呢?让我们假设有这样一个链表,每个元素都严格小于它的后继元素。每个元素都能访问到自己的前驱元素和后继元素(如果有的话)。另外,我们知道每个元素在内存中的地址,因此可以进行随机存取。或者可以说,这个有序链表中的所有元素都是储存在一个数组中的,但数组本身并不有序。
现在,我们需要在这个链表中寻找一个指定的数x。你能否设计出一个平均复杂度低于O(n)的算法来?
这个图形有什么牛B的地方?
这是一个由“L”形三联骨牌拼成的图形。你能看出这个图形有什么神奇的地方吗?
答案:每一个“L”形板块都与另外四个“L”相邻。这是目前已知的满足这种性质的最小构造。“中心对称”并不是我们想要的答案。我们能用“L”形骨牌轻易构造出大量满足中心对称的简单图形来。