天平称球问题(二)

12球的问题看似解决了,但是120球称5次呢?下面我将解释一些原理,给大家提供参考,这样以后无论遇到多少个球,你都能知道最少需要多少次了。

下面的证明有很多不严密的地方,请指正。

 

原理0

天平每次称量形成三种情况(左重、平、右重),那么对未知任何信息的一堆球,称量n次的最多可以分辨(3^n-1)/2个球中坏球的轻重

 

证明:假设称量n次可以分辨的最大球数是x,那么每个球都可能是坏球,并且每个球都可能轻,也可能重,所以共2x种可能。而天平秤n次可以形成3^n种不同结果,那么2x<=3^n,结合3^n是奇数的性质,可得x<=(3^n-1)/2

或许可能有人问,我可以边称量,边根据判断进行剪枝,并没有所有的球都称很多次,是否可以认为总的可能性无法达到2x呢?其实不然,因为每次称量都是将一些可能的坏球排除了可能,放入了好球堆,实质就是从2x中扣除一部分可能,而一旦这部分球含有坏球,那么滤除的可能性立即颠倒过来,信息总量是不会变的。

 

原理1by nice_cxf):

如果一堆球的个数是3^n个,已知一部分球可能偏重,另一部分可能偏轻,则可以在n次称量中找出坏球,并知道坏球轻重。(注意,这个原理的前提是,每个球只能有两种状态,要么是好球或轻球,要么是好球或重球)

例如:假设已有3^4=81个球,其中11个可能偏重(换言之,如果坏球在这11个里,就是重坏球),另外70个可能偏轻(如果坏球在这70个里,就是轻坏球),那么结论是可以通过4次称量找出坏球,并知道坏球轻重。

 

证明(数学归纳法):

基础

当有3^1 = 3个球时,可考虑3021(另外两种情况,1203同理)

30  左右各放一球,哪边重哪个就是重球,如平,则是第三个重

21  左右各放一个可能重球,哪边重哪个就是重球,如平,则是第三个轻

归纳

已知部分可能偏重部分可能偏轻的情况下,假设3^n个球可以用n次称量找出坏球

3^(n+1)个球可能有以下三种情况:

1> 可能重球数量>=2*3^n,也就是总数的2/3

2> 2*3^n>可能重球数>3^n,也就是在总数的1/32/3之间

3> 可能重球数<=3^n,也就是总数的1/3

第三种情况和第一种情况同理,所以只分析前两种情况的策略

第一种情况:天平两端各放3^n个可能重球,如果某一端重,则坏球在这一端里,并且确定坏球是重球,数量缩减到3^n;如果平衡,则天平两端共计2*3^n个球都是好球,坏球在剩下的3^n个球中,数量缩减到3^n,并且依然知道哪些球可能偏重,哪些球可能偏轻。

第二种情况:天平左端放ceil((3^n)/2)个可能重球和floor((3^n)/2)个可能轻球,右端也一样,使得两边都是3^n个球,并且两端的可能重球数和可能轻球数分别相等。结果可能是i左重,ii平,iii右重,由于iiii同理,只考虑前两种结果。

(i):左重,那么坏球只能存在于左边的可能重球和右边的可能轻球,共3^n个。

(ii):平,天平两端都是好球,那么坏球只能存在于剩下的3^n个中。

 

原理2

在原理1的基础上,n次是必然可以找出的最少次数。

 

证明:假设n不是最少的次数,还有小于n次的方案k次(k<n),那么天平每次称量是3种情况,总结果的情况是3^k个,而坏球可能是3^n个球中的任何一个 (每个球如果是坏球,只有一种可能,不用乘以2),3^k<3^n,所以不可能用3^k表示3^n种可能,假设错误,即n是能够保证分辨的最少次数。

 

推论1

根据原理2的证明还可以知道,如果已知n次称量才能找出坏球,那么第一次称量,天平两端最好放3^(n-1)个球,这些球一旦包含坏球,就可以在n-1次称量出来,因为天平两端的球数必须相等,所以,如果有额外的好球,那么就可以两边都放(3^(n-1)+1)/2个球,如果没有额外的好球,两边就只能放(3^(n-1)-1)/2个球

 

原理3

假设称n次知道坏球轻重,能够分辨的最大球数为f(n),则f(n) = (3^n-3)/2

 

证明:

一堆球,第一次称量,必然是左边放一些,右边放一些,留下一些,这样才能使称量次数尽可能少。称量结果可能是平或不平。

如果平,则坏球存在于没放天平的球中,因为天平上的都是标准球,可以应用推论1介绍的方法。

如果不平,则坏球存在于天平上的球中,可以应用原理1

这两种情况,应该尽可能用同样的次数分辨出来。

 

按照上面的描述,如果n次能够分辨的最大球数为f(n),则n+1次最大称量数可如下计算:

天平左右放置的筹码总数为3^n-1(减去1是因为筹码总数是偶数),不放天平的球至少可以辨别f(n)+1(当需要辨别不放天平的球,说明天平上的球都是好球,则有了额外的标准球,应用推论1的方法)

所以f(n+1) >= (f(n)+1) + (3^n-1) = f(n) + 3^n

可以迭代下去f(n) >= f(n-1) + 3^(n-1) = 3^(n-1) + 3^(n-2) + …

边界条件是f(2)=3,所以可以推出f(n) >= (3^n-3)/2

 

假设有了标准球后,不放天平的球至少可以辨别f(n)+2个,则

f(n+1) >= ( f(n)+2 ) + ( 3^n -1 ) = f(n) + 3^n + 1

可以迭代下去f(n) >= f(n-1) + 3^(n-1) + 1 = 3^(n-1) + 1 +3^(n-2) + 1 + …

边界条件是f(2)=3,所以可以推出f(n) >= ( 3^n + 2n - 7 )/ 2,与原理0矛盾。

所以假设错误,不放天平的球最多可以辨别f(n)+1个,所以

 

f(n) = f(n-1) + 3^(n-1) = 3^(n-1)+ 3^(n-2) + … = (3^n - 3)/2

 

原理4

假如称n次找坏球但无需知道坏球轻重,那么能够辨别的最大球数是g(n) = ( 3^n - 1 ) / 2

例如,称3次,那么如果只需要找出坏球即可,可以从13个球中找出坏球。

 

证明:
还是看第一次称量,第一次称量,天平两端的总数尽量要接近
3^(n-1)个,现在条件减弱了,能否放3^(n-1) + 1个球呢?

答案是不能,因为如果坏球存在于天平上的球中,那么经过第一次称量,每个球是坏球的属性都唯一了,只要知道哪个球是坏球,立即可以知道它的轻重,而如果仍然在n-1次称量出来,那么就又相当于用3^(n-1)种结果去分辨3(n-1) + 1种可能性了。所以天平上最多还是放3^(n-1)- 1个球。

 

如果坏球在没称过得球中,那么由于有了标准球,类似推论1,可以得到

g(n) >= g(n-1) + 1 + ( 3^(n-1)- 1 )

由边界条件g(2) = 4, g(n) >= ( 3^n - 1 ) / 2

 

但是我不知道如何证明恰好等于。


指导性意见

 

任给x个球,根据原理3可以算出至少需要称量n次。

 

第一次,天平两端各放(3^(n-1) - 1 ) / 2个球,如果坏球在这些球里面,根据原理1的归纳方法进行后续称量;如果坏球在另外的球里,则从天平那拿出一个标准球,和剩下的球中的3^(n-2) 个球放在一起,平分后放在天平两端,……,后续的步骤都是类似的。

 

下面举例说明120个球的称法

 

根据原理3,可以知道需要n=5次能够称量出来。

 

第一次,天平两端各放( 3^4 - 1 ) / 2 = 40 个球。

 

如果不平,则坏球在这80个球里,其中40个可能偏重,40个可能偏轻。根据原理1的归纳,分别在天平两端放上ceil( 3^3 / 2 ) =14个可能重球,floor( 3^3 / 2 ) = 13个可能轻球,天平两端都是27个球,剩下26个球,这样,无论轻重,都能讲问题规模缩减到26或者27个的样子,可以继续应用原理1

 

如果第一次称量就是平,则放在天平上的80个球都是好球,拿出1个,从剩下的40个球中拿出3^(n-2) = 3^3 = 27 个球,共28个球,天平每边放14个,如果天平不平,则27个球已经知道可能轻重,可以应用原理1

 

否则还剩下13个球,从其中选择3^(n-3) = 3^2= 9 个球,再拿出一个标准球,天平两端各放5个,如果不平,已经知道了9个球的可能轻重,应用原理1

 

否则还剩下4个球,从其中选择3^(n-4) = 3^1 = 3 个球,再拿一个标准球,天平两端各放2个,如果不平,知道了3个球的可能轻重,可以应用定理1

 

否则还剩下一个球,用一个标准球和它一称便知。


信息论中的小球称重问题通常是一个经典的算法谜题,也被称为“最小称量数找出不同质量物品”的问题。这个问题通常涉及到n个大小未知的小球,你需要确定每个小球的质量,但是只有一台可以精确测量两个物品总重量的天平。 在Java中解决这个问题,你可以采用分治策略,特别是分查找法,因为每比较都可以将待确定的小球范围缩小一半。下面是基本思路: 1. 将所有球分为两组,分别放在天平两端。 2. 如果天平平衡,则较轻的那个球在未被选择的那一堆中,通过分查找找到它。 3. 如果天平不平衡,那么较轻的那一侧放着较轻的球,继续将这一半的球分成两组,重复上述过程直到找到唯一的轻球。 4. 找到轻球后,再用同样的方法找出其具体的质量差异。 以下是简单的伪代码示例: ```java public int findHeaviest(int[] weights) { if (weights.length == 1) return 0; // 唯一一颗球直接返回其重量 Arrays.sort(weights); // 先排序,便于区分轻重 int half = weights.length / 2; // 使用分查找确定轻球位置 int minDifference = Integer.MAX_VALUE; for (int i = 0; i <= half; i++) { int diff = Math.abs(weights[half] - weights[i]); if (diff < minDifference) { minDifference = diff; } } // 再天平找具体轻多少克 int[] left = new int[half], right = new int[half]; System.arraycopy(weights, 0, left, 0, half); System.arraycopy(weights, half, right, 0, half); int heavierIndex = binarySearch(left, right, minDifference + weights[half]); return heavierIndex * 2; } // 分查找辅助函数 private int binarySearch(int[] arr, int target) { // ... 实现分查找 ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值