zoukankan      html  css  js  c++  java
  • 一百层高楼和两个棋子

    这个很老的问题我很早就见到过了,答案当时也看了,只是感觉解答很强大,不曾多一点思考。直到上学期网友告诉我tencent的实习面试也考了这个问题,我才发现原来自己不曾真正的搞懂,遂就有了这篇文章(唠叨一下,2009春tencent的校园招聘曾考过远古时代的strlen递归,2009的暑期实习生又考这个问题,充分体现了tencent的创新精神)。

    问题表述:
    现有一百层高楼和两个棋子,棋子从X层上掉落摔到地面刚好摔碎(即X层以下是摔不碎的) 请问至少需要多少次摔棋子试验就一定能够找到X层是第几层? (棋子摔碎了就不能再用了)

    解答:
    假设第一次在第c1层测试;
    1)如果摔碎,那么在1..c1-1层只能一层一层测试;总共需要c1次
    2)如果没摔碎,那么在c1+(c1-1)层测试;
    3)如果摔碎,那么在c1+1..c1+(c1-1)层只能一层一层测试;总共需要c1次
    4)如果没摔碎,那么在c1+(c1-1)+(c1-2)层测试;
    。。。
    所以摔c1次可以检测到的总层数为:1+2+3+...+c1
    1+2+3+...+c1 >=100 ==> c1=14



    看看你能想到上述的方法吗?我是不行,只能逻辑思维了:

    假设第一颗在第 c1 层测试,有两种可能:
    1) 摔碎
    2) 没摔碎
    对于情况 1,说明 X 在 1 到 c1 之间,用递增法,c1 - 1 次可测得。加上第一次,共测试 c1 次。
    对于情况 2,说明 X > c1,于是进行第二轮。


    【第二轮】
    对于情况 2,用第一颗在第 c2 层测试(c2 > c1),有两种可能:
    2.1) 摔碎
    2.2) 没摔碎
    对于情况 2.1,说明 X 在 c1 + 1 到 c2 之间,用递增法,c2 - c1 - 1 次可测得。加上前两次,共测试 c2 - c1 + 1
    次。
    对于情况 2.2,说明 X > c2,进行第三轮。


    【第三轮】
    对于情况 2.2,用第一颗在第 c3 层测试(c3 > c2),仍有两种可能:
    2.2.1) 摔碎
    2.2.2) 没摔碎
    对于情况 2.2.1,说明 X 在 c2 + 1 到 c3 之间,用递增法,c3 - c2 - 1 次可测得。加上前三次,共测试 c3 - c2 + 2
    次。
    对于情况 2.2.2,说明 X > c3,进行第四轮。


    以此类推下去,直到第 n 轮 c(n) >= 总楼层数(即 100),这时候没摔碎的情况已经不会出现。测试结束。
    总测试次数为:
    max {
      c1,
      c2 - c1 + 1,
      c3 - c2 + 2,
      c4 - c3 + 3,
      ...
      c(n) - c(n-1) + (n-1)
    }
    为什么求这些值的最大值呢,因为只有这些值之中的最大值才能满足覆盖到100层楼的次数。什么意思?
    举个例子,看下面四个数字
    5
    4
    8
    6
    虽然最后一个是6,但是临界点如果在8,那么你6次就不能够测出这个位置,这也就是为什么取区间内的最大值了。

    题目中说,求最少多少次能够测出,在这里也就是说,如何让这个最大值最小化。
    观察这个数列(c1, c2 - c1 + 1, c3 - c2 + 2,….)你会发现前一项与后一项的关系,如果前一项特别大的话,就会是后一项特别小。那么为了使最大值比较小的话,就要让这些项都相等,于是
    c2 = 2 * c1 - 1
      c3 = c1 + c2 - 2 = 3 * c1 - 3
      c4 = c1 + c3 - 3 = 4 * c1 - 6
      ...
      c(n) = n * c1 - n(n-1)/2

    以上,即保证在 n 轮 c1 次测试中,必能穷尽 c(n) 层楼。
    现在,我们要求测试次数最少,也就是求 c1 的最小值(每一项都是c1的增函数,如果c1最小,函数也会最小)。


    因为 c(n) >= 100
    所以 n * c1 - n(n-1)/2 >= 100
    即 c1 >= 100/n + (n-1)/2 = 100/n + n/2 - 1/2 >= 2 * sqrt(100/n * n/2) - 1/2 =
    13.6
    (以上用到均值不等式)
    因此 c1 的最小值为 14,即最少需要测试 14 次。
    分别在 14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100 层进行 12 轮测试。

    如果你感觉黄色部分你很难理解的话,这里由一个转化成数学题的解法,十分直观明了,就是不好想到
    其实楼主所贴的第一个解答是很漂亮的. 它已把本题化为如下极值问题:

    对任意自然数n, 以及满足c1 < c2 < ... < c(n-1) < c(n) = 100 的任意n个自然数c1,c2,...c(n), 定义

    多元函数
      f(n,c1,c2,...c(n)) =
      max {
          c1,
          c2 - c1 + 1,
          c3 - c2 + 2,
          c4 - c3 + 3,
          ...
          c(n) - c(n-1) + (n-1)
      }
    求f的极小值

    只是在后面求此极小值的过程让楼主有疑问.我在这里试着把求值过程更形式化一些,希望能解决楼主的疑问

    .

    由f的定义知:

       f >= c1
       f >= c2 - c1 + 1
       f >= c3 - c2 + 2,
       f >= c4 - c3 + 3,
       ...
       f >= c(n) - c(n-1) + (n-1)
      
    把上面n个式子相加,得:
       n*f >= c(n) + 1 + 2 + 3 + ... + (n-1)
            = 100 + 1 + 2 + 3 + ... + (n-1)
            = 100 + n(n-1)/2

    因此, f >= 100/n + (n-1)/2 = 100/n + n/2 - 1/2 >= 2 * sqrt(100/n * n/2) - 1/2 = 13.6
    因为f只能取整数,上式表明f的值是大于等于14的. 当然,仅据此还不足以说明f的极小值就是14, 因为我们

    还不知道f能否取到14. 这时候,用一个取到14的实例就完成了关于f的极小值为14的结论:

      分别在 14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100 层进行测试.

    这么经典的问题,信息论当然不会放过,看一看信息论的解法:
    这题可以转化为信息论来解,两颗碎棋子,表示100种不同的状态,其中存在碎1颗和碎2颗的情况,求最短的编码长度。

    碎了为1,不碎为0,这样的话,100层楼就可以转化为100种不同的01编码,
    编码中最多允许有2个1,也可以只有一个1,比如14层碎了,然后从1试到13都没有碎,编码就是10000000000000。
    对应的是14楼。


    即:C(n,1) + C(n,2) >= 100,其中C(n,1)表示碎1颗的情况,C(n,2)表示碎2颗的情况。

    n + n*(n-1)/2 >= 100
    =>
    n(n+1) >= 200
    =>
    n >= 14

    用这种信息编码的方式考虑这道题,可以把问题扩展到m层楼,n个棋子,而不只局限于当前这道题。LZ可以试试1000层楼,
    3个棋子的情况,用这种编码方式可以很轻松的求得解
    对于信息论,咱知道的也不多,不过网上的资料不少,LZ可以自行搜索一下,
    有不少问题都可以用信息论求得一个下限,比如经典的12彩球问题,另外附带一大堆用天平秤球的问题都可以用信息论来解。
    再比如论坛里以前讨论过的一个赛马的问题。

    对于1000层,3颗棋子,第一次实验的层数,只需要求得

    c(n,3) + c(n,2) + c(n,1) >= 1000 其中的n就可以了,如果碎了,问题就转化为2颗棋子n层楼,
    如果没有碎,问题转化为3颗棋子1000-n层楼

  • 相关阅读:
    SVN服务器搭建(一)
    排序算法二:冒泡排序
    【LeetCode】136. Single Number
    【LeetCode】217. Contains Duplicate
    【LeetCode】189. Rotate Array
    【LeetCode】122. Best Time to Buy and Sell Stock II
    【LeetCode】26. Remove Duplicates from Sorted Array
    【LeetCode】20. Valid Parentheses
    【LeetCode】680. Valid Palindrome II
    【LeetCode】345. Reverse Vowels of a String
  • 原文地址:https://www.cnblogs.com/dmesg/p/1546901.html
Copyright © 2011-2022 走看看