试题4 测试次数
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
注意:需要填写的是一个整数,不要填写任何多余内容。
解题思路:
我自己在思考这道题目的时候,对题目最后要求的条件产生了疑惑,题目最后要求是在最佳策略,在最坏的运气下最多需要测试次数,并且是确定了手机的耐摔指数。
也就是说有以下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;
}
参考博客: