很有意思的一道动态规划问题,记录一下一个比较实用的算法
题目描述
X 星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
X 星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的 2 楼。
如果手机从第 7 层扔下去没摔坏,但第 8 层摔坏了,则手机耐摔指 =7。 特别地,如果手机从第 1 层扔下去就坏了,则耐摔指数 =0。 如果到了塔的最高层第 n 层扔没摔坏,则耐摔指数 =n。
为了减少测试次数,从每个厂家抽样 3 部手机参加测试。
某次测试的塔高为 1000 层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
思路
有一个手机
当我们只有一个手机时,我们只能老老实实从第一层开始扔,第一层没碎就再从第二层扔,第二层没碎就再从第三层扔,,,,最后在k+1层时碎了,那么这个手机的耐摔指数为k。
有两个手机
有两个手机了!我们就可以用点更快的方法去测试了,因为我们碎了一个手机还有另一个。
假设我们需要k次测试,
我们随便选i1层楼开始
i1层
如果碎了那么我们就从1~i1-1层继续测试,但这时我们只有一部手机了,只能从1层开始到i1-1层结束,老老实实一层一层的扔,
最坏的情况是手机的耐摔指数为 =i1-1,
那么我们需要进行测试的次数为1+[(i1-1)-(1)+1)]=i1,
并且保证i1<=k(解题关键)。
如果没碎那么我们就跳到i2层继续测试。
i2层
如果碎了那么我们就从i1+1~i2-1层继续测试,但这时我们只有一部手机了,只能从i1+1层开始到i2-1层结束,老老实实一层一层的扔,
最坏的情况是手机的耐摔指数为 =i2-1,
那么我们需要进行测试的次数为1+1+[(i2-1)-(i1+1)+1]=i2-i1+1,
并且保证i2-i1+1<=k。
如果没碎那么我们就跳到i3层继续测试。
i3层
如果碎了那么我们就从i2+1~i3-1层继续测试,但这时我们只有一部手机了,只能从i2+1层开始到i3-1层结束,老老实实一层一层的扔,
最坏的情况是手机的耐摔指数为 =i3-1,
那么我们需要进行测试的次数为1+1+1+[(i3-1)-(i2+1)+1]=i3-i2+2,
并且保证i3-i2+2<=k。
如果没碎那么我们就跳到i4层继续测试。
i4层
。。。。
i5层
。。。。
。。。。
。。。。
ik层
如果碎了那么我们就从i(k-1)+1~ik-1层继续测试,但这时我们只有一部手机了,只能从i(k-1)+1层开始到ik-1层结束,老老实实一层一层的扔,
最坏的情况是手机的耐摔指数为 =ik-1,
那么我们需要进行测试的次数为1+1+1+…+1+[(ik-1)-(i(k-1)+1)+1]=ik-i(k-1)+(k-1),
并且保证ik-i(k-1)+(k-1)<=k。
如果没碎那么我们就跳到**i(k+1)**层继续测试。
Look!
i1<=k
i2-i1+1<=k
i3-i2+2<=k
。
。
。
ik-i(k-1)+(k-1)<=k
好像可以消元!
消元后
ik+1+2+3+…+(k-1)<=k2
ik<=k2-(k-1)*k/2
ik<=(k+1)*k/2
如果有一百层的话,ik=100,那么k的最小值就为14,是不是很有意思?
有三个手机
*当一个第一个手机碎了,那么我们就有两个手机了,意味着又可以使用关系式 ik<=(k+1)k/2了
假设我们需要K次测试,
我们随便选i1层楼开始
i1层
如果碎了那么我们就从1~i1-1层继续测试,但这时我们有两部手机了,通过关系式n<=(k+1)k/2*
注意n代表的是楼层数!
最坏的情况是手机的耐摔指数为 =i1-1,
n=(i1-1)-(1)+1=i1-1,
k=K-1(解题关键)
那么并且保证i1-1<=(K-1) * K/ 2(解题关键)。
如果没碎那么我们就跳到 i2层继续测试。
i2层
如果碎了那么我们就从i1+1~i2-1层继续测试,但这时我们有两部手机了,通过关系式n<=(k+1)*k/2
最坏的情况是手机的耐摔指数为 =i2-1,
n=(i2-1)-(i1+1)+1=i2-i1-1,
k=K-2
那么并且保证i2-i1-1<=(K-2) *(K-1)/ 2。
如果没碎那么我们就跳到 i3层继续测试。
i3层
。。。。
i4层
。。。。
。。。。
。。。。
ik层
如果碎了那么我们就从i(k-1)+1~ik-1层继续测试,但这时我们有两部手机了,通过关系式n<=(k+1)*k/2
最坏的情况是手机的耐摔指数为 =ik-1,
n=ik-i(k-1)-1,
k=K-K
那么并且保证ik-i(k-1)-1<=(K-K) *(K-K-1)/ 2。
如果没碎那么我们就跳到 i(k+1)层继续测试。
Look!
i1-1<=(K-1) * K/2
i2-i1-1<=(K-2) * (K-1)/2
i3-i2-1<=(K-3) * (K-2)/2
。
。
。
ik-i(k-1)-(k-1)<=(K-K) * (K-K-1) /2
消元!
ik-k<=(1/2)*[K * (K-1)+(K-1) * (K-2)+(K-2) * (K-3)+ …+(K-K) * (K-K-1)]
运算技巧
ik-k<=(1/2)*{[K * K+(K-1) * (K-1)+(K-2) * (K-2)+ …+(K-K) * (K-K)]-[(K)+(K-1)+(K-2)+(K-3)+…+(K-K)]}
ik-k<=(1/2)*{[K * K * K /3 +K * K /2 +K /6 ]-[(K+1) * K] / 2}
ik-k<=(1/2) * (K * K * K/3 -K /3 )
ik<=K * K * K/6+5 * K /6
按题目要求,此处ik应为1000,求解后,k=19
按此规律还可以求出有4个、5个、6个手机的情况
代码
import os
import sys
# 请在此输入您的代码
k=1
while True:
k+=1
if k**3+5*k>=6000:
print(k)
break
编码不易,点个赞支持一下吧!~~~