小球称重问题:用天平称量几次才能找到有问题的球?

在n个外观完全相同的小球中,有一个与其它球重量不同。如何只用一架天平找到这个球并判断它比其它球轻还是重?最少需要称几次?

这是一个流传极广的经典问题,在网上随便一搜就会发现无数人都提出了自己的见解和算法并争论不休。最常见的是12个小球,至于更多球的计算,就不是人力能及的了。

实际上,这个问题确实是有准确答案的:n次称量最多可以在个球中找到不同的球,并判断它的轻重。
理论证明可参考The Problem of the Pennies, F. J. Dyson, The Mathematical Gazette , Vol. 30, No. 291 (Oct., 1946), pp. 231-234。
不过这里不打算讲那么多理论,而是直接演示怎么称量并找到这个小球。

算法十分精巧,我尽可能简单地描述了一下。如果还是觉得太抽象,没关系,直接点击这里或者拉到下面看演示就可以了。

  1.  编码
    知道了球数,就能算出需要称量几次;
    以这个次数作为长度,使用0、1、2排列组合进行编码,如001021、212022等等,再去掉全0、全1和全2,可知一共有个编码;
    如果在一个编码中,第一处相邻数字不同的情况是01、12或20,则我们称它为正序码,如1120021;
    否则为逆序码,如2221012;
    在长度为n的编码中,正序码和逆序码的数量相等,均为个。
  2. 赋值
    如果把一个正序码中的0换成1,1换成2,2换成0,则它仍然是正序码;
    根据这个原理,我们把所有正序码按3个3个进行分组,如12001、20112、01220这3个就是一组;
    把正序码一组一组地分配给小球,每球一个,直到分完;
    然后把每个正序码的0换成2,2换成0,它就变成了一个逆序码,如12001变成10221;
    这样,每个小球就有了两个编码,一个正序,一个逆序,而且所有球都不重复。
  3. 称重
    第一轮,我们把所有正序码第一位为0的小球放在天平左侧,为2的小球放在右侧,其它的放在旁边;
    如果天平左倾,记为0;右倾,记为2;平衡,记为1;
    然后是第二轮,把第二位为0的小球放在左侧,为2的放在右侧,同样记下称量结果;
    每一轮都按这个顺序进行,一共要称n次,最终结果是个n位的编码;
    如果编码等于某个小球的正序码,则这个小球比其它球重;
    如果编码等于某个小球的逆序码,则这个小球比其它球轻。

下面就是这个算法的完整演示:

首先输入球数,电脑会自动给所有球编码;然后手工设置某个特殊球是轻还是重;接下来就会自动分组称量,最终找到特殊球,看看是否和你所设置的那个一致。
在本演示中,绿色代表轻;红色代表重。

补充说明:

  1. 如果小球的数量是3的倍数,则上面的算法完全没有问题,但如果不是3的倍数,则要做如下处理:
    小球数量除以3,余1,则给多出来的这个球分配以1开头的编号;
    小球数量除以3,余2,则给多出来的这两个球分配一组编号中以0和2开头的两个。
    这样的话,第一轮称重的天平左右两侧球数必然相同。
    而且每一轮称重后,都会有1/3或2/3的球被证明是重量正常的。所以如果后面出现天平左右球数不等,就找一个正常球补到少的一边,或者从多的一边取走一个正常球即可。
  2. 此算法适用于大于3的任何球数,限于浏览器性能,最多可输入999个;
  3. 本演示程序参考了知乎问题有999个乒乓球其中有一个和其他的质量不同,问你用天平最少几次一定能称出来?答案中洪涛提供的文章和陳浩的算法解释,在此特别致谢。
5+

10 comments

发表评论

电子邮件地址不会被公开。 必填项已用*标注