玻璃球安全测试问题

  • 一、 问题背景介绍
  • 二、固定步长测试
  • 三、动态规划
    • (1)两个玻璃球的情况
    • (2)三个玻璃球的情况
  • 四、Python实现
    • (1)尝试
    • (2)最终方法与Python代码

一、 问题背景介绍

玻璃球如果从一定的高度掉到地上会摔碎。
假设这个恰巧摔碎的高度为 F F F层
任何从高于或等于 F F F的楼层落下的玻璃球都会碎,从比 F F F层低的楼层落下的玻璃球都不会碎。
给你 K K K个玻璃球,如何测试出恰好摔碎的楼层 F F F?

二、固定步长测试

首先,先从两个小球的情况开始考虑,假设第一个球每次跨过 M M M层(如:从1层到 M M M+1层),假如玻璃球在恰巧 M M M+1碎了,则使用第二个小球便从1层到 M M M层逐层测试即可。
那么如果总楼层为100层,则最小测试次数 K K K的公式为:
K = [ 100 M + 1 ] + M K= \left[\frac{100}{M+1}\right]+M K=[M+1100​]+M
用Python来计算一下 K K K的最小值:

for M in range(1,30):print(M,': ', 100//(M+1)+M)

Python输出结果为:

1 :  51
2 :  35
3 :  28
4 :  24
5 :  21
6 :  20
7 :  19
8 :  19
9 :  19
10 :  19
11 :  19
12 :  19
13 :  20
14 :  20
15 :  21
16 :  21
17 :  22
18 :  23
19 :  24
20 :  24
21 :  25
22 :  26
23 :  27
24 :  28
25 :  28
26 :  29
27 :  30
28 :  31
29 :  32

可以看出在步长在7-12之间时,测试次数 K K K达到最小值19。

然而经过简单分析便能得知固定步长得出的结果一定不是最小的。

举个简单的例子:假如有两个玻璃球使用9为步长来计算21层楼需要测试的最小值,那么第一个球将会从第10层扔下,假如没有碎再从第20层扔下,此时的最坏情况是第一个小球从第20层扔下时摔碎了,此时只能用第二个小球从第11层测试到第19层,测试次数为11次。然而想要测试次数更小的话,便可以将第一个球将会从第10层扔下没碎后,再将小球从16层扔下,此时最坏情况是小球碎了,那么第二个小球便需要从第11层测试到第15层,此时测试只需要7次。

由此可见固定步长的方法是不能将测试次数将为最小的,不过也提醒我们需要根据具体的情况确定具体的策略。

三、动态规划

(1)两个玻璃球的情况

有了上面一种测试方法的经验,现在的改进思路便是最大程度利用小球可测试的层数。

假设还是使用两个玻璃球进行测试,这一次不再规定楼层高度,而是思考在规定次数内如何测试最多的楼层,这样得到最大可测楼层 N N N后,只需要找到满足到 N ⩾ M N\geqslant M N⩾M( M M M为总层数)时 N N N的最小值所对应的测试次数即可。因此第一个小球第一次释放的层数应该依据剩下的一个球在剩余次数里最多能测试多少层来确定。

假如规定次数为5次,那么第一个小球从哪里落下合适呢?答案应该是第5层。原因是:如果第一个小球从第5层仍落时恰好摔碎,剩下的一个小球恰好可以使用余下的4次机会逐一测试第1层到第4层,同样的思路假如小球从第5层掉落没有摔碎,那么下一次小球下落的楼层应为第9层,因为小球在第9层摔碎,剩下的一个小球也可以在剩下的3次机会内,测试第6层到第8层。以此类推,第一个小球可以跨过的层数便为4层,3层,2层,和1层,而第一个小球释放层数应为:第5层,第9层,第13层,第14层。假如第一个小球在第14层下落也没碎,那么便可以用剩下的最后一次机会测试第15层,因此最多可测试层数便为15层。

用测试次数T计算最大可测试层数N的公式便是:
N = [ T ( T − 1 ) 2 ] + 1 N=\left[\frac{T(T-1)}{2}\right]+1 N=[2T(T−1)​]+1

(注:这个公式其实就是等差数列求和公式)

(2)三个玻璃球的情况

有了两个玻璃球的基础,再思考三个玻璃球的情况时,确定第一个球跨过楼层的个数应为剩下两个球在剩余次数中最多可测试的层数。

例如一共有6次测试次数,第一个球释放楼层数应是剩下两个球在剩余次数中最多可测试的层数+1,也就是: [ 6 ( 6 − 1 ) 2 ] + 1 \left[\frac{6(6-1)}{2}\right]+1 [26(6−1)​]+1

而第一个小球第二次下落层数便是: [ 6 ( 6 − 1 ) 2 ] + 1 + [ 5 ( 5 − 1 ) 2 ] + 1 \left[\frac{6(6-1)}{2}\right]+1+\left[\frac{5(5-1)}{2}\right]+1 [26(6−1)​]+1+[25(5−1)​]+1
以此类推三个玻璃球的最大可测试层数N公式便为: N = ∑ i = 1 T ( [ i ( i − 1 ) 2 ] + 1 ) N=\sum_{i=1}^T (\left[\frac{i(i-1)}{2}\right]+1) N=i=1∑T​([2i(i−1)​]+1)

四、Python实现

(1)尝试

首先,先对两个球和三个球的情况进行初步尝试:

两个玻璃球:

for k in range(1,10):print(k)floor=0for i in range(1,k):floor+=i*(i+1)/2+1print(floor)

输出结果:

1
0
2
2.0
3
6.0
4
13.0
5
24.0
6
40.0
7
62.0
8
91.0
9
128.0

三个玻璃球:

for k in range(1,10):print(k)floor_4 = 0for p in range(1,k):floor_3 = 0for i in range(1,p):floor_3 += i*(i+1)/2+1floor_4 += floor_3print(floor_4)

输出结果:

1
0
2
0
3
2.0
4
8.0
5
21.0
6
45.0
7
85.0
8
147.0
9
238.0

其中k为测试次数,floor为最大可测试层数。

从输出结果看,可以看出最明显的问题便是:最开始的输出为0。也就是说4个小球测试1次最大可测试楼层为0。然而实际上结果应当为1。

出现这个问题的原因是:

    for p in range(1,k):for i in range(1,p):

当for循环时,i最多只能取到p-1,因此当p=1时,i的范围是1-0,for循环便不能进行下去了。

考虑解决 K K K个小球问题需要一层一层迭代,而这个出现的问题又比较棘手,下面便会介绍一种可行的实现方法。

(2)最终方法与Python代码

这个方法是为了弄清上面那个由于“玻璃球个数大于测试次数”引起的问题时所制作的“玻璃球个数与测试次数对应最大可测楼层层数”表格(每个单元格的值根据之前介绍的公式很容易计算)。

玻璃球个数 测试1次 测试2次 测试3次 测试4次 测试5次
1 1层 2层 3层 4层 5层
2 1层 3层 6层 10层 15层
3 1层 3层 7层 14层 25层
4 1层 3层 7层 15层 30层

与前面得出的公式原理相同,但从表格可以清楚的看出之前所使用的原理:第一个球释放的楼层数应是剩下 N N N-1个球在剩余次数中最多可测试的层数+1。 因此,表格中某一格的值=左面格子的值+左上方格子的值+1。

举个例子:3个玻璃球测试4次可测的最高楼层为:6层+7层+1层=14层。

这便为计算最大楼层提供了一个新的思路:利用球数和测试次数定位并使用上述规律逐行计算。

Python代码:

ball = int(input('玻璃球个数:'))
time = int(input('尝试次数:'))
line_1 = list(map(lambda x:x, range(1,time+2-ball)))def line_2(line_1):line = [1]for i in range(1,len(line_1)+1):x=line[i-1]+1+line_1[i-1]line.append(x) return linefor i in range(0,ball-1):line_1 = line_2(line_1)

在上述代码可以输入玻璃球的个数和测试次数计算最大可测楼层。
如果是想输入玻璃球个数和总楼层数计最小测试次数,会有很多实现方法。
这里先提供一个解法(这个并不是最简单的转换方法,但是思路是最直接的):

ball = int(input('玻璃球个数:'))
floor = int(input('总楼层数:'))
time = 5
line_1 = list(map(lambda x:x, range(1,time+2-ball)))cont=-1def line_2(line_1):line = [1]for i in range(1,len(line_1)+1):x=line[i-1]+1+line_1[i-1]line.append(x) return linefor i in range(0,ball-1):line_1 = line_2(line_1)while cont==-1:if line_1[-1]<floor:time+=5line_1 = list(map(lambda x:x, range(1,time+2-ball)))for i in range(0,ball-1):line_1 = line_2(line_1)else:    for i in range(0,len(line_1)):if line_1[i]>=floor:cont=i+1print('最小测试次数:',cont)break

当然这个转换的方法不是最有效率的,提供一个改进的思路:发现最大楼层依旧小于总楼层时,可以让time变大,并从目前得出的最大楼层继续计算。这样就会比重新计算到新的time效率更高。

任意个数玻璃球安全测试问题解析与Python实现相关推荐

  1. java远程代码注入_Java RMI远程反序列化任意类及远程代码执行解析(CVE-2017-3241 )...

    原标题:Java RMI远程反序列化任意类及远程代码执行解析(CVE-2017-3241 ) 本打算慢慢写出来的,但前几天发现国外有研究员发了一篇关于这个CVE的文章,他和我找到的地方很相似.然而不知 ...

  2. Java黑皮书课后题第5章:5.2(重复加法)程序清单5-4产生了5个随机减法问题。改写该程序,使它产生10个随机加法问题,加数时两个1到15之间的整数。显示正确答案的个数和完成测试的时间

    5.2(重复加法)程序清单5-4产生了5个随机减法问题.改写该程序,使它产生10个随机加法问题,加数时两个1到15之间的整数.显示正确答案的个数和完成测试的时间 题目 题目概述 程序清单5-4 破题 ...

  3. 【Python】输入任意个数元素并保存至列表

    目录 1.导入任意个数元素到列表 1.1.编程思路 1.2.代码片 2.查找一个重复元素在列表中的所有位置 2.1.编程思路 2.2代码片 1.导入任意个数元素到列表 1.1.编程思路 输入未知个数的 ...

  4. python支持任意大的数字_Python实现接受任意个数参数的函数方法

    这个功能倒也不是我多么急需的功能,只是恰好看到了,觉得或许以后会用的到.功能就是实现函数能够接受不同数目的参数. 其实,在C语言中这个功能是熟悉的,虽说实现的形式不太一样.C语言中的main函数是可以 ...

  5. Postman测试导入/解析excel接口的方法

    Postman测试导入/解析excel接口的方法 看不懂的新人可以不用去理解,直接拿去用就行了. 上接口源码 private static final String XLSX = ".xls ...

  6. 围绕企业服务总线的测试解决方案及测试场景解析

    背景 企业服务总线概述 企业服务总线,即ESB全称为Eenterprise Service Bus,指的是传统中间件技术与XML.Web服务等技术结合的产物.随着金融系统的架构体系日渐复杂.各系统间交 ...

  7. 任意遥控器遥控C1测试成功,理论上可使用任意遥控

    转自:http://bbs.letv.com/thread-35538-1-1.html http://bbs.letv.com/thread-65155-1-1.html 任意遥控器遥控C1测试成功 ...

  8. 比大小,人类智慧天花板,任意类型,任意个数。内容包含函数模板的创建,类的创建,动态内存的分配与释放,函数调用指针的用法。牵扯多个知识点。

    比大小,看这一篇就足够,大家好,我是姜姜一名热爱C++编程的大学生,接下来我将通过代码演示如何利用C++实现任意类型,任意个数的比大小,并且找出最大的数. 由于本人比较懒,所有没写注释还请各位读者多多 ...

  9. java map 多个key_java ListMap使用多个或者任意个数的key进行排序

    使用JAVA自己的排序方法,有的时候是一个可行的选择. 先从简单的开始说起. 一.少数key的情况 有一个需求:根据 menu_level,sort排序,越小的越前面. -- 下面代码按照升序规则进行 ...

最新文章

  1. CentOS 6虚拟机安装
  2. vue打包后图片找不到情况
  3. POJ-3278-Catch That Cow
  4. 链表最终总结【数据结构】
  5. sql server numeric 可存几位小数_CBA中的10大传奇队长,将篮球精神一直传递下去,你认识几位呢?...
  6. Pandas Timedelta对象
  7. Image合并添加文字内容
  8. 将数字转化为字符串的两种方法
  9. PDN仿真笔记5-电容走线影响寄生电感的因素分析
  10. 软件开发的43款可视化工具
  11. 不可小觑的吃内存大户
  12. flex布局实现不换行且不挤在一起效果
  13. 对日软件外包企业的发展思考(转)
  14. macbook 终端命令怎么使用_mac终端命令大全 苹果入门
  15. 美国小学教育——转自顾小北
  16. 大话设计模式之爱你一万年:第二十三章 行为模式:解释器模式:在也不用担心工资计算错误了:3.解释器模式之简单计算器3.0
  17. 2023年BeijngCrypt勒索病毒家族最新变种之.halo勒索病毒
  18. 用 css 实现文本前面的空格
  19. C#winform任务栏显示小图标及右击操作
  20. PHP加速和部署多主机LAMP架构

热门文章

  1. 爬取妹子图(python):爬虫(bs+rq)+ gevent多线程
  2. Dynatrace 新增业务关键绩效指标异常检测及分析,提升用户体验与业务绩效
  3. 微信小程序引入阿里巴巴图标库
  4. 可完全分离的二维矢量图加密域鲁棒可逆水印算法(一)
  5. 不堆砌公式,用最直观的方式带你入门深度学习
  6. 对Probabilistic Road Map(PRM)概率路图路径规划方法的理解
  7. HDUOJ 2066 一个人的旅行——
  8. vim 批量查找替换
  9. 关于QQ抓包,IP准确性的问题
  10. java 反斜杠_java反斜杠\的用法 | 学步园