蓝桥杯第09届 2018年省赛C/C++大学生B组——试题4 测试次数

本文通过动态规划解决了一个关于手机耐摔指数测试次数的问题。在限定的手机数量和高楼层数下,寻找最佳策略以最小化最坏情况下的测试次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

试题4 测试次数

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

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

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

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

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

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

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

解题思路:

我自己在思考这道题目的时候,对题目最后要求的条件产生了疑惑,题目最后要求是在最佳策略,在最坏的运气最多需要测试次数,并且是确定了手机的耐摔指数。

也就是说有以下4个条件:

  1. 最佳策略
  2. 最坏运气
  3. 最多需要测试的次数
  4. 确定出了手机的耐摔指数

按题目的意思就是:3部手机,最坏运气就是全部摔坏,并且最后一次恰好得出手机耐摔指数。

假设楼高H层

针对1部手机的时候,我们从第1层开始摔起,当第K层摔坏了,那么就耐摔指数就是K-1

针对2部手机的时候,我们可以不从第1层开始摔,我们选取中间一层,比如第K层摔起,那就有两种情况:

  • 手机在第K层坏了,那么我们就剩下1部手机,那就需要判断1部手机在K-1层高度的楼里的测试次数,最后把这个测试次数+1,就是手机的耐摔指数。
  • 手机在第K层没有坏,那么我们还有2部手机可以使用,那接下来需要判断的是2部手机H-K层高度的楼测试次数,同样最后测试次数+1,就是手机的耐摔指数。

注意:这里有一个问题,不知道大家有没有发现。按理来说,K层没有坏,需要判断的是K+1层到H层楼的情况,但是这里实际上,如果你将楼层看做测试次数的话,你会更好理解。也就是说,从第K层摔下,如果坏了,那你还有K-1次测试次数,如果没有坏,那么你还有H-K次测试次数。

最后,综上所述,如果有N部手机的话,并且M层高的楼。那么我们的用 dp[i][j] 来表示 i 部手机从 j 层楼高的最少测试次数的话那就是:

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

注意:中间有一个max,这里解释下:这里取max是因为i部手机j层楼有dp[i][j]次测试机会,我们必须确保在这个次数内所有情况的耐摔指数都要能被测出来,如果取了较小的那个,次数多于它的情况就没法确保被测试出来。

C++代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

int dp[4][1005]; //dp[i][j]  表示i部手机从有j层的楼测试的最少次数 

int max(int a, int b) {
	return a > b ? a : b;
}

int min(int a, int b) {
	return a > b ? b : a;
}

void fun(int phoneNum, int headNum) {
	// 初始化数组
	for(int i=1;i<=phoneNum;i++) {
		for(int j=1;j<=headNum;j++) {
			dp[i][j] = j;// 先初始化上最大的可能性,也就是每层楼都扔一遍 
		}
	}
	// i从2开始,因为1部手机就不需要测了,最坏运气下的最多情况是每层的高度 
	for(int i=2;i<=phoneNum;i++) {
		for(int j=1;j<=headNum;j++) {
			// 计算dp[i][j]的k的所有可能值,这里不等于j
			// 原因是数组会越界,第二没有必要,因为从j层扔下,就是原来最大化的初始值 
			for(int k=1;k<j;k++) {
				dp[i][j] = min(dp[i][j], max(dp[i-1][k-1], dp[i][j-k])+1);
			}
		}
	} 
}

int main(int argc, char** argv) {
	fun(3, 1000);
	cout<<dp[3][1000]<<endl;
    return 0;
}

参考博客:

  1. 第九届蓝桥杯省赛C++B组 测试次数 作者:ryo_218
  2. 第九届蓝桥杯第四题 测试次数 (动态规划入门)作者:亓官劼
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hiram Fan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值