[面试题][总结]100层楼丢玻璃球测试临界可破层数,用两个一模一样的球来测试计算尽可能少的次数?

1 题目描述

   有一栋100层高的大楼,给你两个完全相同的玻璃球。假设从某一层开始,丢下玻璃球会摔碎。那么怎么利用手中的两个球,用什么最优策略知道这个临界的层是第几层?

2 解法汇总

2.1 递推方法一

  第一次扔k层 ,则次数time=1,第二次,如果破了,要试从1到k-1层,此时需要Time=time+k-1=k 次;如果没破,还要扔k层,则次数为time=2;如果破了,还要扔k+1到2k-1层,再加上2 即Time=Time+k-2=k。还是K次;注意每多扔一次 少测试一层。次数却多一次。实际只要能测到n-1层就够了。

  以此类推如果满足 k+(k-1)+(k-2)+(k-3)+(k-4)+....+2+1 >= n-1 。可以化简得到:k(k-1)>=2(n-1)

这里,n=100 所以 解得k=14。所以只要14次就可以确认那层试临界层。

2.2 图形法

首先从题目得出基本思路

1.第一个球应该低到高试,但不是每层必;

2.不能有侥幸心理,第二个球在第一个球的区间里每层必。

  上图是简化为10层楼解法。数字代表楼层,球从原点先右后上的路径对应的方格中的数字进行测试.也就是第一个球测试4\7\9\10层.如果第一个球4层坏了,第二个球测试1\2\3。如果第一个球7层坏了,第二个球测试5\6。依次类推,肯定可以测出最终的层数。这样做摔4次肯定能得出结果,是最优的方案。

  如果把上图的每一个层看作一个1*1的正方形。上图就近似一个等腰梯形,面积为4*4/2+4*0.5=10,也就是层数。推广开来,对于边长为N的图形,它所能测试的层数就是N*N/2+N*0.5。对于M层楼,最优方案只是上图的类推。将1到M按照上图类同的方法排布,并按照先右后上的路径。这肯定是最优解。也就是N*N/2+N*0.5〉=M。这里只要取得N的最小正整数就是最多的尝试次数。比如100层的情况是: N*N/2+N*0.5>=100。解得N的最小正整数解是14。

  从数学证明的角度来看:最优解是怎样的呢?问题已经可以转化为在坐标系的原点出发,只能先右后上的,在相同的面积下,哪一种图形的使得原点到该图形的任意一点的距离的最大值最小。结论是:在相同的面积中,直角等腰的三角形到达面上的任意一点的最大距离是最小的。直角等腰三角形的斜边上任意一点到达原点的距离都是一样的,也是直角等腰三角形中距离原点最大的。利用反证法,如果还有比直角等腰三角形更好的图形,必然要挖去斜边上所有的点,但是把这些点放在哪里呢?放在哪里都比现在的位置远。

2.3 动态规划

  设f(a, b)为a个球做b次测试可以测试到的楼层数,可以确定的楼层数即为f(a, b) + 1,因为第1层不需测试,需要测试的楼层号仅仅为[2, f(a, b) + 1]共f(a, b)层,也就是a个球b次测试可以测试到的楼层数。考虑第1次测试,测试的楼层记为x:

1)如果球破了,就需要测试x下面的楼层,还剩下a-1个球b-1次测试,测试的楼层数为f(a - 1, b - 1)。

2)如果球没有破,那么需要测试x上面的楼层,还剩下a个球b-1次测试,测试的楼层数为f(a, b - 1)。

a个球b次测试为1)2)测试的楼层数及第1次测试了的1层,所以:

f(a, b) = f(a - 1, b - 1) + f(a, b - 1) + 1                                              (1)

考虑初始条件,显然f(a, 1) = 1(a >= 1,1次测试可以测试到的楼层数当然为1,不论多少个球),f(1, b) = b(b >= 1,1个球做了b次测试当然测试到了b层楼)。

强调一下:注意f(a, b)为测试到的楼层数,f(a, b)加上不需测试的楼层才是可以确定的楼层(f(a, b) + 1)。

一般来说,a >= 2(1个球意义不大),可以计算出f(2, 64) = 2080,f(3, 64) = 43744,f(4, 64) = 679120。

  1 /*
  2  * a balls, n floors, want to find the minimum number of floor
  3  * where a ball drops will be broken. output the minimum number
  4  * of drops
  5  * METHOD: dynamic programming
  6  * assum the answer is b, that is the number of drops
  7  * f(a, b): the maximum number of floors, when a balls and b drops
  8  * f(a, b) = 1 + f(a, b - 1) + f(a - 1, b - 1)
  9  * obviously, f(a, 1) = 1; f(1, b) = b
 10  */
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <assert.h>
 14 #include <string.h>
 15 #define DEBUG
 16 #define MAX_B 64
 17 #define MAX_A 16
 18 #define f(a, b) ff[a - 1][b - 1]
 19 static unsigned int a, n;
 20 static unsigned long long ff[MAX_A][MAX_B];
 21 static void init()
 22 {
 23     int i;
 24     memset(ff, 0, sizeof(ff));
 25     /*f(a, 1) = 1*/
 26     for (i = 1; i <= MAX_A; i++){
 27         f(i, 1) = 1;
 28     }
 29     /*f(1, b) = b + 1*/
 30     for (i = 1; i <= MAX_B; i++){
 31         f(1, i) = i;
 32     }
 33 }
 34 static unsigned long long do_find_min_drops(int i, int j)
 35 {
 36     if (f(i, j))
 37         return f(i, j);
 38     f(i, j) = do_find_min_drops(i - 1, j - 1) +
 39         do_find_min_drops(i, j - 1) + 1;
 40     return f(i, j);
 41 }
 42 static void do_print_drops(int i, int j, unsigned long long min,
 43         unsigned long long max)
 44 {
 45     if (min > max)
 46         return;
 47     if (1 == i){
 48         assert(j == max - min + 1);
 49         for (i = min; i <= max; i++){
 50             printf("%5d", i);
 51         }
 52         printf("/n");
 53         printf("*************/n");
 54         return;
 55     }
 56     if (1 == j){
 57         assert(min == max);
 58         printf("%5lld/n", max);
 59         printf("*************/n");
 60         return;
 61     }
 62     printf("%5lld", min + f(i - 1, j - 1));
 63     do_print_drops(i - 1, j - 1, min, min + f(i - 1, j - 1) - 1);
 64     do_print_drops(i, j - 1, min + f(i - 1, j - 1) + 1, max);
 65 }
 66 static void print_drops(int ans)
 67 {
 68     do_print_drops(a, ans, 2, n);/*[2..n]*/
 69 }
 70 static void find_min_drops()
 71 {
 72     /*NOTE: number of floors are [1, n]*/
 73     int i, j, m;
 74     int ans;
 75 #if 0//def DEBUG
 76     for (i = 2; i <= MAX_A; i++){
 77         for (j = 2; j <= MAX_B; j++){
 78             printf("f(%d, %d) = %lld/n", i, j, do_find_min_drops(i, j));
 79         }
 80         printf("****************/n");
 81     }
 82 #endif
 83     i = 1;
 84     j = MAX_B;
 85     while (i <= j){
 86         m = (i + j) / 2;
 87         if (do_find_min_drops(a, m) + 1 < n)
 88         /*
 89          * why +1? because the 1st floor need not to test
 90          */
 91             i = m + 1;
 92         else
 93             j = m - 1;
 94     }
 95     ans = i;
 96     if (ans > MAX_B){
 97         printf("the number of the maximum drops(MAX_B = %d) is too small/n", MAX_B);
 98         printf("maximum floors "
 99                 "can be tested is f(%d, %d) + 1 = %lld + 1. STOP/n", a, MAX_B, f(a, MAX_B));
100         exit(0);
101     }
102     printf("the minimum drops: %d/n", ans);
103     print_drops(ans);
104 #ifdef DEBUG
105     for (i = 1; i <= a; i++){
106         for (j = 1; j <= ans; j++){
107             printf("f(%d, %d) = %lld/n", i, j, f(i, j));
108         }
109         printf("****************/n");
110     }
111 #endif
112 }
113 int main(int argc, char **argv)
114 {
115     if (3 != argc){
116         fprintf(stderr, "usage: %s a n/n", argv[0]);
117         exit(-1);
118     }
119
120     a = atoi(argv[1]);
121     n = atoi(argv[2]);
122     printf("a = %d/tn = %d/n", a, n);
123     assert(a > 0 && a < MAX_A && n > 0);
124     init();
125     find_min_drops(); /*drops: 1*/
126     return 0;
127 }  

1)2个球,100层楼时,可以计算出

f(2, 13) = 91
f(2, 14) = 105

  因此需要的测试次数为14。

2)3个球,100层楼,可以计算出

f(3, 8) = 92
f(3, 9) = 129

  因此测试测试最多为9次。可以从38层开始。

原文地址:https://www.cnblogs.com/kuliuheng/p/11595153.html

时间: 2024-08-24 22:38:28

[面试题][总结]100层楼丢玻璃球测试临界可破层数,用两个一模一样的球来测试计算尽可能少的次数?的相关文章

[程序员面试题精选100题]10.排序数组中和为给定值的两个数字

扩展(1):输入一个数组,判断这个数组中是不是存在三个数字i, j, k,满足i+j+k等于0. 扩展(2):如果输入的数组是没有排序的,但知道里面数字的范围,其他条件不变,如何在O(n)时间里找到这两个数字?这个的基本思路是先用哈希表实现O(n)的排序(请参照本面试题系列的第57题),接下来的步骤都一样了.

[程序猿面试题精选100题]10.排序数组中和为给定值的两个数字

剑指Offer之和为S的两个数字 剑指Offer之和为S的连续正数序列 扩展(1):输入一个数组,推断这个数组中是不是存在三个数字i, j, k,满足i+j+k等于0. 扩展(2):假设输入的数组是没有排序的,但知道里面数字的范围,其它条件不变,怎样在O(n)时间里找到这两个数字?这个的基本思路是先用哈希表实现O(n)的排序(请參照本面试题系列的第57题).接下来的步骤都一样了.

两个运动球的相交性测试

[两个运动球的相交性测试] 首先,两个运行的球,可以转化为一个静止,一个运动的相对运动. 其后,利用三角公式,按下图原理,即可计算出t. 最后化简,可得最后公式: t有一大一小俩值,小的是开始接触的值,大的是结束接触的值.如果t小于0,则无交点.

100层楼2个鸡蛋

有一栋楼共100层,一个鸡蛋从第N层及以上的楼层落下来会摔破, 在第N层以下的楼层落下不会摔破.给你2个鸡蛋,设计方案找出N,并且保证在最坏情况下, 最小化鸡蛋下落的次数. 设最坏情况下的次数为K,如果第一个鸡蛋第一次就在x层摔坏,则第二个鸡蛋应该从第1层开始试到x-1层,最坏还要试x-1次,则总测试次数为1+(x-1)= K,x=k; 如果第一个鸡蛋第一次在x层没坏,第二次摔坏了,此时已经测试了2次了,则第二个鸡蛋最坏能够测试k-2次,设第二次摔坏的层数为y,则第二个鸡蛋应该从x+1层开始测试

poj 3783 DP 2个鸡蛋扔100层楼的加强版

http://poj.org/problem?id=3783 估计23号之后的排位赛之后我就要退役了,这之前最后再做5天ACM 今天的排位很惨,上次排位也很惨......这道题原来算法课老师讲过,模模糊糊记得方程,但是边界处理有问题, dp[i][j]=min(1+max(dp[k-1][j-1],dp[i-k][j]))   k=1 to 楼数 dp[i][j]:i层楼扔,手里有j个ball 的次数 边界两个:1.dp[1][i]=1,第一层无论手里有几个鸡蛋都是1次,2.dp[i][1]=i

100 层楼两个鸡蛋

有座 100 层高楼和软硬程度一样但未知的两个鸡蛋,要求用这两个鸡蛋以最少的次数确定哪一层是鸡蛋可以安全落下的最高位置.鸡蛋有可能在一楼就摔碎,也可能在一百楼摔下也没事. 假设 L 层鸡蛋没碎,L+1 层碎了,则 L 层就是所求.因为只有两个鸡蛋,所以第一个鸡蛋摔碎后,一定要能用第二个鸡蛋在限定的次数里测出目标层. 考查一个中间状态,假设最少的次数为 C. 之前已经测了 C0 次(C0<C) 层数为 L0,测到 C0+1 次层数 L1 为时,第一个鸡蛋碎了.则第二个鸡蛋就从 L0+1 层测到第

穿越两次PIX8.0防火墙并两次静态NAT的FTP测试

一.测试拓扑 二.测试思路 客户端和Server端不能直接通讯,都作了一对一的静态NAT 当客户端采用被动模式的FTP连接FTP服务器端时,FTP的控制通讯和数据通讯,发起端都在客户端: ----对于客户端侧防火墙来说,都是从高安全区到低安全区的访问,无需放通策略; ----对于服务端防火墙来说,控制通讯是从低安全区到高安全区的访问,因此,需要开放针对TCP21的策略;数据通讯也是从低安全区到高安全区的访问,端口随机,因此需要配置ftp审查. 当客户端采用主动模式的FTP连接FTP服务器端时,F

xtrabackup 备份mysql数据库三: innobackupex 测试一个全量和两个增量的备份恢复测试

## 查看当前库中表的数据 ([email protected]) [test]>select count(*) from t_innodb; +----------+ | count(*) | +----------+ |        0 | +----------+ 1 row in set (0.00 sec) ## 执行插入数据操作,该操作在全备之后执行完成 ([email protected]) [test]>call addTest(100000,0); ## 执行全库备份 #

IT公司100题-14-排序数组中和为给定值的两个数字

问题描述: 输入一个升序排序的数组,给定一个目标值target,求数组的两个数a和b,a+b=target.如果有多个组合满足这个条件,输出任意一对即可. 例如,输入升序数组[1, 3, 4, 5, 13, 17]和目标值20.输出3和17. 分析: 最简单的办法,直接遍历,时间复杂度为O(n^2). 双下标法:low和high a[low]+a[high] < target, low++; a[low]+a[high] > target, high–; a[low]+a[high] == t