一个有趣的问题-分球问题
最近给我们学校的一个提高班的招新考试出了一道笔试题,是关于常见的称球问题,大部分人都知道这题,也会觉得不屑一顾,如果我已经知道方法了我也许同样会这么觉得,但我总习惯站在一个旁观者的角度审查问题,就像这次出的这题,我就重新思考了一下这个问题,发现还是大有文章可做的,如果你肯花费10分钟看下我下面这段文字,相信会对你有所帮助的。废话不多说了,让我们开始吧!这是一个历史悠久的问题:有n(n≥3)个球,其中一个是次品,你有一架天平,但没有砝码,现在要用最少的称量次数判断出次品来。
这个问题初看上去很简单,但细想起来还真不是一眼能看出来的,我是个非常喜欢物理学的童鞋,这里的让我想起大学物理里讲到过的熵,这是我最喜欢的概念,信息熵也是一个非常棒的想法,信息是个很抽象的概念。我们常常说信息很多,或者信息较少,但却很难说清楚信息到底有多少。比如一本五十万字的中文书到底有多少信息量。直到 1948 年,香农提出了“信息熵”(shāng) 的概念,才解决了对信息的量化度量问题。当然这个量化也是做了一个标准的,在此就不提多了,要不然没人往下看了,呵呵。
总之,我想用信息熵的办法解决这个问题,当然其他办法也有很多,我只是表达自己观点。
这里有n个球,其中一个是次品,我们可以认为每个球都有可能是次品,而且一个球是次品还是正品的概率是等值的,都是1/2,由独立事件的概率乘法可知,任何一种情况的概率为1/2的n次方。假设我们手上有一个检验器,可以瞬间检验出一个球是否是正品,那么我们只需要用它来检验每一个球,直到出现次品为止,我们考虑最坏的情况,即检验到最后一个球才是次品,于是说明在进行检验前信息熵为S2 = K*ln(2的n次方)= log2(2的n次方)= n(bit),于是我想到可以用一串01串来代表这些球,一个球对应一个数,为0即正品,为1即次品。
我们知道称量一次会出现两种情况,平衡和不平衡。于是我们可以设法分别求出每一次称量之后的熵变,当然这里需要信息论的知识,因为我信息论了解不多,自然无法得出答案。呵呵~~其实我是没有尝试成功的,但不代表我永不会成功。我上网找了很久,也看了很多大家的解法,最后我看到了长沙雅礼中学的何林同学的解法,相当的不错,这里推荐给大家他的思路,当然,我也希望你们能像我一样,尝试自己能想到的各种方法,即使最后不能成功,也是有助于开拓思路的。
先给出我根据何林同学的计算公式写的一段简单代码,大家可以自己运行一下,玩一下嘛~~
- #include <stdio.h>
- #include <math.h>
- void main()
- {
- int choose = 0;
- int m = 3;
- int n = 6;
- int i, j;
- int X = 1;
- double temp1, temp2, temp3;
- const double eps = 1e-10;
- while (65534 > (i++))
- {
- printf("Please choose set the number of\nblancing times or balls(1 for times,2 for balls): ");
- scanf("%d",&choose);
- if (1 == choose)
- {
- printf("Input the number of blancing times(number >= 3 & <= 10): \n");
- while (1)
- {
- scanf("%d",&m);
- if ((3 <= m) && (10 >= m))
- {
- for (j = 0; j < m; j++)
- {
- X *= 3;
- }
- X -= 1;
- X /= 2;
- printf("You can most blancing %d balls!!\nPlease test again\n\n\n\n", X);
- X = 1;
- break;
- }
- else
- {
- printf("Wrong Input number,please input again: \n");
- continue;
- }
- }
- }
- else if (2 == choose)
- {
- printf("Input the number of balls(number >= 4 & <= 65535): \n");
- while (1)
- {
- scanf("%d",&n);
- if ((4 <= n) && (65535 >= n))
- {
- n = 2 * n + 1;
- temp1 = log(n);
- temp2 = log(3);
- temp3 = temp1 / temp2;
- printf("You can least blancing %d times!!\nPlease test again\n\n\n\n", (((temp3-(double)((int)temp3)) < eps) ? (int)temp3 : ((int)temp3 + 1)));
- break;
- }
- else
- {
- printf("Wrong Input number,please input again: \n");
- continue;
- }
- }
- }
- else
- {
- printf("Wrong Input,please reinput!!!\n\n");
- continue;
- }
- }
- printf("That's enough!!!\n");
- }
下面是何林同学的部分思路,最后我附上他的整份文档和PPT以及他自己写的一端pascal程序,因为暂时没有经过他本人的同意就放这里了,所以希望大家不要用作不良用途~~
转载于:https://blog.51cto.com/rangercyh/416526