蓝桥杯-测试次数

标题:测试次数

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。

各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。

x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。

如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。

特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。

如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n

为了减少测试次数,从每个厂家抽样3部手机参加测试。

某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?

请填写这个最多测试次数。

注意:需要填写的是一个整数,不要填写任何多余内容。

答案:19

思路1:动态规划。

首先,我们再来看一遍题目的问题:从每个厂家抽样3部手机参加测试,某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?什么叫最佳策略,什么又叫最坏运气下(这里最多是匹配最坏运气说的)?翻译一下就是:摔死了3部手机并且测试到最后一次才能测出耐摔指数所需要的最少测试次数。

好了,那么我们下面要想办法找出这个最少的测试次数。这里我们可以设这个测试次数为k次,3部手机一共测试k次可以测出耐摔指数。既然有k次机会,我们不妨就把第1部手机先从第k层楼摔下去。如果第1部手机摔死了,那么第2部手机剩下k-1次机会,可以从1k-1层来测试。如果第1部手机没摔死,那么它还剩下k-1次机会,那我们下次就可以从第k+(k-1)层楼摔。如果它这一次摔死了,那么第2部手机还有k-2次机会,就可以从k+1k+(k-1)-1层来测试。如果第1部手机在第k+(k-1)层摔下来后仍旧活下来了,那么它还有k-2次机会,在下次就可以从第k+(k-1)+(k-2)层摔。以此类推,一定可以在k次内测出耐摔指数。

那么有人就要说了,你这里只说了2部手机,可是我们有3部手机啊。其实情况是一样的,假如我们有n部手机m层楼,第1部手机在第k层摔死了,那么接下来要测试的就是n-1部手机k-1层楼的情况,如果没摔死,就测试n部手机m-k层楼的情况(人会有主观意识觉得楼层越高越容易摔死,但是那不一定,手机也有可能到1000层都摔不死呢,所以测试情况的时候我们可以只看层数,k+1m和1m-k是一样的)。

综上所述,我们可以推出动态转移方程:dp[i][j]表示i部手机j层楼的最少测试次数,dp[i][j]=max(dp[i-1][k-1],dp[i][j-k])+1,k∈[1,j-1](这里取max是因为i部手机j层楼有dp[i][j]次测试机会,我们必须确保在这个次数内所有情况的耐摔指数都要能被测出来,如果取了较小的那个,次数多于它的情况就没法确保被测试出来)。我们一开始在给dp数组初始化的时候,可以全部初始化为它的最坏情况,j层楼的最坏测试次数是j次,就是每层楼都要摔一次,那么我们这里用了最佳策略后,次数就应该小于等于这个值,方程就可以变化为:dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1),k∈[1,j-1]。

思路2:手算。

让我们继续……n部手机m层楼要在最少的k次测试中测出耐摔指数,因为我们事先并不知道这个耐摔指数到底是多少,也就是说这m层楼的每一层楼(每一个耐摔指数)的情况都要能在这k次中测试出来,于是问题可以转化成:n部手机k次测试最多可以测出多少层楼。

先数字小一点,用2部手机来分析好了。老样子,第1部先从第k层摔,死了就第2部从1~k-1层测试,这种情况显然不是最多的。那么如果第1部手机完好无损,它还有k-1次机会,下次可以从第k+(k-1)层摔,这里我们第1次摔就测试了k层楼,如果第2摔也没问题那么我们就测试了k+(k-1)层楼了,既然要求最多可以测出的楼层,按照这个思路,自然是每次摔下去都没死才能测到的最多,于是可以得出式子:

能测出的最多楼层要大于等于题目给出的楼层m就能求出这个次数k了:

2部手机的情况很好理解,接下来我们来分析3部手机k次测试的情况,稍微复杂一点点。根据上面的推导,我们知道2部手机k-1次机会的话可以测出层楼。现在3部手机,第1部手机从第层摔下,如果摔死了,那么就是剩下的2部手机对1~层的测试,如果没摔死,那么就是从第层摔,和上面是差不多的道理啦,然后得出式子:

题目给的是1000层,那么得出k最小为19。

以上均是这位大佬写的
https://blog.csdn.net/ryo_218/article/details/79810705

import java.util.*;

public class Main{
	public static int phone = 3,floor = 1000;
	public static int[][] dp = new int[5][1100];
	public static void main(String[] args){
		for(int i=1;i<=phone;i++){
			for(int j=1;j<=floor;j++){
				dp[i][j] = j;
			}
		}
		for(int i=2;i<=phone;i++){
			for(int j=1;j<=floor;j++){
				for(int k=1;k<=j-1;k++){
					dp[i][j]=Math.min(dp[i][j],Math.max(dp[i-1][k-1],dp[i][j-k])+1);
				}
			}
		}
		System.out.println(dp[3][1000]);
	}
}

笔记:
1.n部手机测试m层楼求最少测试次数问题可以转化为这样一个dp方程

dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1)

其中 i 部手机测试 j 层楼,耐摔属性为 k,如果第一次 k 层摔碎,则只有 i-1 部手机 从头开始测试 k-1 层 ,如果没碎,那么有 i 部手机继续往上测试 j-k 层楼,两种情况取得最大的测试次数,再加上第 k 层测的一次,最后更新初始化的dp值。
2.dp初始化尽量少,一定要准确,可以只初始化一次,尽量选择可以一次初始化 n 个的值或者初始化0和1的特殊值,这里就是初始化 i 部手机 j 层楼 最大就是 j 次,然后不断用min更新出结果,其中楼层低的 j 可以更新的更小。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值