第九届蓝桥杯省赛真题JAVAB组第四题 测试次数

题目:
标题:测试次数

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。

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

如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n

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

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

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

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

解题思路:

题目问题:1000层楼,三部手机,最坏的运气下最多测试多少次能得到摔坏前的最高层。将问题进行转换:3部手机,测试k次,最多能测试多少层?

首先,先考虑两部手机,测试k次,最多能测试多少层?

进行第一次测试,先测第k层,消耗了一次测试机会,剩下k-1次测试机会。手机摔坏了,那么剩下的另一部手机只能从第一层开始一层一层的测试,测到第k-1层(共测了k-1层)。加上第一次测的那一层,这样测试k次,最多能测(k-1)+1层

如果第一次测试时,手机没坏,那么第k层及其以下层都是安全的。

进行第二次测试,手机坏了,此时剩下k-2次测试机会,另一部手机测k-2次,只能测k-2层,所以第二次测试应该测第[(k-1)+1]+[(k-2)+1]层,最多能测[(k-1)+1]+[(k-2)+1]层

如果第二次测试时,没有坏。

进行第三次测试,手机坏了,此时剩下k-3次测试机会,另一部手机测k-3次,只能测k-3层,所以第三次测试应该测第[(k-1)+1]+[(k-2)+1]+[(k-3)+1]层,最多能测[(k-1)+1]+[(k-2)+1]+[(k-3)+1]层

......

如果第j-1次测试时,没有坏。

进行第j测试,手机坏了,此时剩下k-j次测试机会,另一部手机测k-j次,只能测k-j层,所以第j次测试应该测第[(k-1)+1]+[(k-2)+1]+[(k-3)+1]+......+[(k-j)+1]层,最多能测[(k-1)+1]+[(k-2)+1]+[(k-3)+1]+......+[(k-j)+1]层

......

如果上述测试过程中,手机一直没有摔坏,直到最后进行第k次测试,应该测试第[(k-1)+1]+[(k-2)+1]+[(k-3)+1]+......+[(k-k)+1]层

那么两部手机,1000层楼,需要测k次才能完成测试,那么:

  [(k-1)+1]+[(k-2)+1]+[(k-3)+1]+......+[(k-k)+1]

=k+(k-1)+(k-2)+......+1

=k(k+1)/2 ≥ 1000

解得:k≥44.22415.....

k需要向上取整,k最少为45。

如果将一部手机进行k次测试的结果用数组保存起来,下角标表示进行第k测试,数组内容表示能够测的最大楼层数,即:

pre[k] = k

则两部手机进行k次测试时,能够测的最大楼层数为:

  [(k-1)+1]+[(k-2)+1]+[(k-3)+1]+......+[(k-k)+1]

=(pre[k-1]+1)+(pre[k-2]+1)+......+(pre[0]+1) ≥ 1000

如果将两部手机进行k次测试时的结果用数组保存起来,下角标表示进行第k测试,数组内容表示能够测的最大楼层数,即:

current[k] = (pre[k-1]+1)+(pre[k-2]+1)+......+(pre[0]+1)

那么current[k-1] = (pre[k-2]+1)+(pre[k-3]+1)+......+(pre[0]+1)

则两部手机进行k次测试时,能够测的最大楼层数为:

current[k] = (pre[k-1]+1)+(pre[k-2]+1)+(pre[k-3]+1)......+(pre[0]+1)

                  = pre[k-1] + 1 + current[k-1]  ≥ 1000

然后,回到正题,三部手机的情况下呢?

先记住两部手机可以推出的结论:两部手机,k次测试,最多能测k(k+1)/2层

三部手机,思路同前面一样,先确定第一次测试时的楼层位置,第一次测试,不能太高也能太矮,必须恰到好处,也就是第一部手机如果摔坏,剩余k-1次机会,用两部手机能够将剩余楼层给测试完。

因为两部手机k-1次测试,最多能测试k(k-1)/2层,所以第一部手机第一次测试时先测第k(k-1)/2+1层

进行第一次测试,先测第k(k-1)/2+1层,消耗了一次测试机会,剩下k-1次测试机会。手机摔坏了,那么剩下的另两部手机只能从第一层开始一层一层的测试,测到第k(k-1)/2层(共测了k(k-1)/2层)。加上第一次测的那一层,这样测试k次,最多能测(k(k-1)/2+1层

如果第一部手机第一次测试时,如果第一部手机没有摔坏,那么第k(k-1)/2+1层及其以下层都是安全的。

进行第二次测试,手机坏了,此时剩下k-2次测试机会,两部手机进行k-2次测试最多能测(k-1)(k-2)/2层,所以第二次测试应该测第[k(k-1)/2+1]+[(k-1)(k-2)/2+1]层,最多能测[k(k-1)/2+1]+[(k-1)(k-2)/2+1]层

如果第二次测试时,没有坏。

进行第三次测试,手机坏了,此时剩下k-3次测试机会,两部手机进行k-3次测试最多能测(k-2)(k-3)/2层,所以第三次测试应该测第[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]层,最多能测[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]层

......

如果第j-1次测试时,没有坏。

进行第j次测试,手机坏了,此时剩下k-j次测试机会,两部手机进行k-j次测试最多能测(k-j)(k-j+1)/2层,所以第三次测试应该测第[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]+......+[(k-j)(k-j+1)/2+1]层。

最多能测[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]+......+[(k-j)(k-j+1)/2+1]层。

......

进行第k次测试,此时剩下0次测试机会,两部手机进行0次测试最多能测0层,所以第k次测试应该测第[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]+......+[(1*0)/2+1]层。

最多能测[k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]+......+[(1*0)/2+1]层。

则三部手机进行k次测试时,能够测的最大楼层数为:

  [k(k-1)/2+1]+[(k-1)(k-2)/2+1]+[(k-2)(k-3)/2+1]+......+[(1*0)/2+1]

如果将两部手机进行k次测试的结果用数组保存起来,下角标表示进行第k测试,数组内容表示能够测的最大楼层数,即:

pre[k] = k(k+1)/2

则三部手机进行k次测试时,能够测的最大楼层数为:

  (pre[k-1]+1)+(pre[k-2]+1)+(pre[k-3]+1)......+(pre[0]+1) ≥ 1000

如果将三部手机进行k次测试时的结果用数组保存起来,下角标表示进行第k测试,数组内容表示能够测的最大楼层数,即:

current[k] = (pre[k-1]+1)+(pre[k-2]+1)+......+(pre[0]+1)

那么current[k-1] = (pre[k-2]+1)+(pre[k-3]+1)+......+(pre[0]+1)

则三部手机进行k次测试时,能够测的最大楼层数为:

current[k] = (pre[k-1]+1)+(pre[k-2]+1)+(pre[k-3]+1)......+(pre[0]+1)

                  = pre[k-1] + 1 + current[k-1]  ≥ 1000

由此看出用三部手机进行k次测试时,需要用到三部手机进行k-1次测试和两部手机进行k-1次测试的数据。

可以推广得到,对于n部手机进行k次测试时,需要用到n部手机进行k-1次测试和n-1部手机进行k-1次测试的数据。

有重叠子问题(current[k-1]),子问题有最优解或可以用有更优解的新子问题(复杂程度更小的pre[k-1] )代替。而动态规划常被用于有重叠子问题和最优子结构性子的问题。可以使用动态规划求解k值,先介绍一下动态规划基本步骤:

  1. 将复杂的问题分解成简单的问题,求解简单的问题,以求解复杂的问题。
  2. 自底向上的求解最小规模子问题的最优解,用一张表将结果记录下来。
  3. 遇到相同子问题,直接查表得到答案。通过一步一步的迭代,就可以得到复杂问题的答案。

动态规划在分解问题的时候,往往可以用递归问题描述,然而递归存在多次重复计算,采用自底上求解最小规模子问题的最优解并记录结果,可以省去重复计算。这样就将递归问题转换成了迭代问题。

这里n部手机k次测试,自底向上求解,用数组记录计算结果:

用数组pre[]存放n-1部手机的测试结果,数组current[]用于存放当前n部手机测试结果。

n=1时:

  • current[k] = k;

n=2时:

  • pre[] = current[];
  • current[k] = pre[k-1]+1+current[k-1]; 
  • current[k]>=1000?

n=3时:

  • pre[] = current[];
  • current[k] = pre[k-1]+1+current[k-1]; 
  • current[k]>=1000?

......

用JAVA代码描述:

                //存放当前n部手机测试结果
		int current[] = new int[m+1];
		//存放n-1部手机的测试结果
		int pre[] = new int[m+1];
		//current初始化,同时存入一部手机的测试数据
		for(int i=0;i<m+1;i++){
			current[i] = i;
		}
		//两部及两部以上的测试情况
		for(int i=2;i<=n;i++){
			pre = current.clone();
			
			current[k] = pre[k-1]+1+current[k-1];
			current[k] >= m?
			
			
		}

我们要寻找的是,k取何值时,current[k]>=m?

k的取值范围应该是1到m(一部手机测试时,k=m时,才满足条件),循环遍历k的所有可能取值,找到满足条件的k值,则跳出循环,并将k值返回,问题得以解决。

                //存放当前n部手机测试结果
		int current[] = new int[m+1];
		//存放n-1部手机的测试结果
		int pre[] = new int[m+1];
		//current初始化,同时存入一部手机的测试数据
		for(int i=0;i<m+1;i++){
			current[i] = i;
		}

		int times = 0;
		//两部及两部以上的测试情况
		for(int i=2;i<=n;i++){
			pre = current.clone();
			
			for (int k = 1; k <= m; k++) {
				current[k] = pre[k-1]+1+current[k-1];
				if (current[k] >= m) {
					//使用变量times存放k值
					times = k;
					//跳出循环块
					break;
				}
			 }
			
			
		}

将以上代码封装成函数,供main函数调用:


public class Main {
	public static void main(String[] args) {
		System.out.println(getTimes(1000, 3));
	}

	/**
	 * 获得测试次数
	 * @param m	楼层数
	 * @param n	手机数量
	 * @return times  测试次数k
	 */
	public static int getTimes(int m,int n) {
		//存放当前n部手机测试结果
		int current[] = new int[m+1];
		//存放n-1部手机的测试结果
		int pre[] = new int[m+1];
		//current初始化,同时存入一部手机的测试数据
		for(int i=0;i<m+1;i++){
			current[i] = i;
		}
		int times = 0;
		//两部及两部以上的测试情况
		for(int i=2;i<=n;i++){
			pre = current.clone();
			
			for (int k = 1; k <= m; k++) {
				current[k] = pre[k-1]+1+current[k-1];
				if (current[k] >= m) {
					//使用变量times存放k值
					times = k;
					//跳出循环块
					break;
				}
			}
		}
		return times;
	}
}

运行结果截图:

参考资料:http://blog.sina.com.cn/s/blog_3fe961ae0101llmf.html

发布了45 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/baidu_41327283/article/details/88624827