100层高楼摔2个鸡蛋的问题?

来源:互联网 发布:java文件上传到数据库 编辑:程序博客网 时间:2024/05/03 02:09

在智力或算法测试中不时地会遇到一种类似的问题:一幢大楼共计100层,某种类型的鸡蛋从某一楼层及其以上楼层摔下来时会被打破,从该层楼(即临界楼层)以下楼层摔下该鸡蛋,鸡蛋不会出现破损。现给你2个完全一样的该种类型的鸡蛋,问:如何通过这2个鸡蛋找到该临界楼层?
思考:给了我们2个鸡蛋,意思就很明显,有1个鸡蛋起到关键作用,它可以被打破,以告诉我们临界楼层大致在什么位置。如果给了我们99个及更多的鸡蛋,我们大致可以正序(2~100)或者倒序地(100~2)来逐层摔鸡蛋,在能摔破鸡蛋和不能摔破鸡蛋的临近两层楼的地方确定了临界楼层的楼层号。给了2个鸡蛋,那么我们可以大胆地想象通过摔破一个鸡蛋来提供给我们有用的信息以评估临界楼层。比如,我们很容易想到折半查找,从51楼摔一下鸡蛋,如果不碎,那么再从76,如果在76碎了,那么,从76和52的中值64处来试探貌似是不ok的,因为如果在64层,第2个鸡蛋也碎了,那么还有区间[53,63]都是可能摔碎鸡蛋的楼层。所以这种折半的方法不太靠谱,除非我们的鸡蛋远远超过2个。从刚才可以看到,我们将区间[2,100]通过折半的方法分成了两个段[2,50]及[51,100],效率是比顺序和倒序的情况(即不分段)好很多的,在折半分段的情况下,我们可以比不分段的情况少打破至少一半以上的鸡蛋,就可以测试出临街楼层。只不过在摔破鸡蛋的每个小段区间里,每个楼层都应该被逐层的试探。好了,这就是我们要的思想。那么,现在的问题是:怎么来合理地分段呢?刚才的折半的方法是非常粗糙的,在鸡蛋很少(只有2个)的情况下,是不可能使用折半查找的。我们大胆地估计一下,如果把100分成10段,那么要找到临界楼层,我们大致最多需要20次测试,我们通过2,12,22,32,...,不断地试探,确定了某个区间,就进入该区间逐个测试。试看:如果临界楼层在10层一下,我测试2楼的时候鸡蛋正常,测试12楼的时候鸡蛋破了1个鸡蛋,我们就回头从3楼,4楼测试到11楼,直到第2个鸡蛋被摔破,就测试出来了(如果鸡蛋不摔破,那么临界楼层就是第12楼),总共试探了11次。同理,如果临界楼层在90几楼,那么,我们从2,12,22,32,...,不断测试应该不超过20次就可以测试出来。到目前为止我们已经取得比较好的结果了。再想想,正方形的面积要比长方形多吧,我们可以不以平均一下,不管临界楼层是在2~12之间还是90~100之间都能在一个比较平均的测试次数下面来把它测试出来呢?试想,我们在90几的临界楼层时,区间大小如果都是固定的,那么对于临界楼层比较大的情形,就多产生了测试次数。我们很容易就想到,可以设想,让区间大小从前往后,逐步减少,让相邻的两个区间,楼层较低的区间段比楼层号较高的区间段多1,这样就保证了无论临界楼层在哪个区间段,我们总能通过同样的试探次数将能将其找出来,平均来说是最优的方案。那么这一切都完美无缺了。这就是我的想法。
解题:假设我们从第2个楼层开始试探,往楼层号码渐次增长的方向,每隔数个楼层,试探一次,并在试探到第1个鸡蛋摔破的地方停下来,用第2个鸡蛋来从最近一次试探没有摔破的楼层之上的那个楼层开始逐个楼层进行试探,知道鸡蛋被摔破,我们就得到了临界楼层,如果鸡蛋一直没有被摔破,那么第一个鸡蛋摔破的楼层就是临界楼层。现在假设第2个楼层和下一次试探的楼层之间有x个楼层,即第2次试探的楼层号是A(2)=x+3,以后试探的楼层间隔分别减少1,那么我们第3次试探的楼层号为A(3)=2x+3,第4次为A(4)=3x+2,第5次为A(5)=4x,第n次为A(n)=(n-1)*x-(1/2)*n*n+(5/2)*n,这里需要注意,我们试探的n不能超过x+1,可以这么想来:跳跃测试的n不应超过第一次最大的跨度(也即第一种需要连续测试的区间大小),及n<=x+1。那么把x替换为n-1,得到A(n)=(1/2)*n*(n+1)+1。楼层为100,那么A(n)=(1/2)*n*(n+1)+1>=100,得到n(n+1)>=198,得n=14,x=13,那么A(n)=(31*n-n*n-26)/2. 即通过楼层2,16,29,41,52,62,71,79,86,92,97,101,(104,106).作为间隔就可以在使用2个鸡蛋,不超过14次测试的情况下找到临界楼层。

其他的解法尚待参考。