趣题:不用乘法实现 (1 + x + x^2 + x^4) mod 2233393

    下面是 IBM Ponder This 2013 年 5 月的谜题:写一个程序来计算 f(x) = 1 + x + x2 + x4 (mod 2233393) 。你的程序只能使用以下三种语句,其中等号表示赋值,变量 2 和变量 3 的位置都可以用常量来代替:

(1) 变量 1 = 变量 2 + 变量 3
(2) 变量 1 = 变量 2 * 变量 3
(3) 变量 1 = 变量 2 mod 变量 3

    很容易想到,一种最基本的解法如下:

a = x * x
b = a * a
c = a + b
d = c + x
e = d + 1
f = e mod 2233393

    这道谜题则要求你找到另外一种解法,它必须同时满足下面两个额外的要求:

      (1) 最多使用两次变量与变量之间的乘法运算(但允许多次变量与常量之间的乘法运算)
      (2) 最后两次运算分别是一次变量与变量之间的乘法运算和一次取余运算

Read more…

通信复杂度问题:确定双方手中所有数的中位数

    通信复杂度(communication complexity)主要研究这么一类问题: A 持有数据 x , B 持有数据 y ,他们想要合作计算某个关于 x 和 y 的二元函数值 f(x, y) ,那么在渐近意义下,两人至少需要传输多少 bit 的数据。最近着迷于通信复杂度,看到了几个与通信复杂度有关的问题,和大家分享一下。下面就是其中之一。

    A 、 B 的手中各有一个 {1, 2, …, n} 的子集。两人想知道,如果把他们手中的数全都放在一块儿,那么这些数(可能会有重复的数)的中位数是多少。然而, A 、 B 两人远隔千里,他们之间通信的成本非常高。因此,他们想在通信线路上传输尽可能少的信息,使得最终两人都知道中位数的值。在这里,为了简便起见,我们直接定义 m 个数的中位数是第 ⌈ m / 2 ⌉ 小的数,因而如果 m = 2k ,那么中位数就应该直接取第 k 小的数。

    其中一种最笨的方法是, A 把手中的所有数全部发给 B 。由于发送一个不超过 n 的正整数最多会用到 log(n) 个 bit ,而 A 手里的数最多有 O(n) 个,因此 A 传给 B 的信息量就是 O(n · logn) 。于是, B 就得到了足够多的信息,可以直接计算中位数了,算好后再把结果告诉 A ,此时又要耗费 log(n) 个 bit (但它并不会成为通信量的瓶颈)。因此,在这种方案中,总的通信复杂度就是 O(n · logn) 。事实上,传送一个 {1, 2, …, n} 的子集只需要一个 n 位 01 串就够了,因而我们可以把通信复杂度降低到 O(n) 个 bit 。

    利用下面的办法,我们可以实现 O(logn · logn) 的通信复杂度。首先, A 、 B 分别告诉对方自己手中有多少个数,这一共会耗费 O(logn) 个 bit 。接下来,两人在区间 [1, n] 上进行二分查找。假设到了某一步,中位数被限定在了区间 [i, j] 里,那么 A 就计算出 k = (i + j) / 2 ,数一数自己手中有多少个数比 k 小,然后告诉 B ,由 B 再来数数自己这边又有多少个比 k 小的数,从而判断出 k 作为中位数来说是偏大了还是偏小了,并把判断出来的结果返回给 A 。根据情况,区间 [i, j] 将被更新为 [i, k] 或者 [k, j] ,两人在新的区间上继续二分下去。整个算法将会持续 O(logn) 轮,每一轮都会传输 O(logn) 的数据,因此总的通信复杂度是 O(logn · logn) 。

    另一方面,通信复杂度至少是 Ω(logn) 的。这是因为,如果规定 A 和 B 最多只能交流 k 个 bit ,那么整个交流历史最多就只有 k 次分岔的机会,到最后最多只能产生 2k 个不同的分支;但事实上中位数有可能是 1 到 n 中的任何一个,共有 n 种不同的可能,因此 2k 必须大于等于 n 。这说明 k 必须大于等于 log2(n) ,也就是说两个人总会有必须要交流 log2(n) 个 bit 才行的时候。

    一个有意思的问题自然而然地诞生了:我们所得的上界和下界仍然有差距。究竟是刚才的算法还不够经济,还是刚才证明的结论还不够强呢?

    还想说明一点的是,两个人商量算法的过程,或者其中一个人把算法告诉另一个人的过程,这可以不算进通信复杂度里。事实上,把它们算进通信复杂度里也没关系,因为它们反正都是 O(1) 的。

Read more…

UyHiP趣题:用最少的称重次数验证硬币的重量

    这是一个非常有趣的问题,它出自 UyHiP May 2013 的谜题。

    假设你有 n 枚外观完全相同的硬币,它们的重量分别为 1g, 2g, 3g, …, ng 。有意思的是,这一次,你已经知道了各枚硬币的重量,而且你也已经把重量值标在了这些硬币上。但是,由于我不知道各枚硬币的重量,因此我希望你能向我证明,你所标的重量值是正确的(我知道这些硬币的重量是从 1 克到 n 克,我只是不知道哪个硬币对应哪个重量)。

    你唯一能用的工具就是一架天平。每一次,你可以任意选择一枚或多枚硬币,放在天平的左侧,再从剩下的硬币中任意选择一枚或多枚硬币,放在天平的右侧(注意,你只能在天平上放硬币,不能放别的东西)。一个有意思的问题是,为了向我证明你所标的重量值都是对的,你最少需要使用多少次天平?

    显然,为了证明 n 枚硬币的重量标签的正确性,我们最多需要称 n – 1 次。先把硬币 1 放在左边,把硬币 2 放在右边,让对方看到硬币 1 确实比硬币 2 要轻。接下来,向对方验证硬币 2 确实比硬币 3 更轻,硬币 3 确实比硬币 4 更轻,等等。称完 n – 1 次后,我们就相当于给出了 n 枚硬币的轻重顺序,因而它们只有可能分别是 1 克 、 2 克 、 3 克……。

    我们还能做得更好吗?不妨让我们看看 n 比较小的情况。例如,当 n = 4 的时候,利用上述方法可以 3 次完成验证,那么只用 2 次可以完成验证吗?仔细一想,你会发现真的可以!其中一种方法就是,先把硬币 1 和硬币 2 放在左边,把硬币 4 放在右边。由于两枚硬币的重量之和小于第三枚硬币,这只可能是 1 + 2 < 4 ,因此对方会相信,左边两枚硬币分别是 1 和 2 ,右边那枚硬币是 4 ,没放上去的那枚硬币是 3 。对方唯一不知道的就是,在左边两枚硬币中,究竟谁是 1 ,谁是 2 。于是,我们只需要再称一下硬币 1 和硬币 2 ,问题就解决了。

    不妨把证明 n 枚硬币重量标签的正确性最少需要的称重次数记作 B(n) 。我们的问题就是:判断 B(n) 是以什么级别增长的。

Read more…

趣题:同时等分三角形周长和面积的直线

    求证:对于任意一个三角形,一定存在一条直线,它把这个三角形的周长和面积同时分成了两等分。

 
 
    大家知道,三角形的三个内角的角平分线一定交于一点,这个点就是三角形的内心,它到三角形三边的距离是相等的。一个令人吃惊的结论是,经过内心的直线如果平分了三角形的面积,就一定平分了三角形的周长!

      

    如图, I 是三角形 ABC 的内心, ID 、 IE 、 IF 是 I 到三角形三边的垂线段,它们的长度是相等的,不妨把这个长度值记作 r 。假设直线 PQ 经过点 I ,并且平分三角形的面积。这说明, PA · r / 2 + AQ · r / 2 = PB · r / 2 + BC · r / 2 + CQ · r / 2 ,也就是 PA + AQ = PB + BC + CQ 。因此,直线 PQ 也平分了三角形 ABC 的周长。

Read more…