目录
题目
题目链接
提交结果截图
详细分析
易懂版:
升级版:
带详细注释的源代码
易懂版:
升级版:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
X 星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
X 星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的 2 楼。
如果手机从第 7 层扔下去没摔坏,但第 8 层摔坏了,则手机耐摔指 =7。 特别地,如果手机从第 1 层扔下去就坏了,则耐摔指数 =0。 如果到了塔的最高层第 n 层扔没摔坏,则耐摔指数 =n。
为了减少测试次数,从每个厂家抽样 3 部手机参加测试。
某次测试的塔高为 1000 层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
测试次数 - 蓝桥云课 (lanqiao.cn)https://www.lanqiao.cn/problems/616/learning/
【误区】我们看到这种“最优策略”、“求次数”,很容易想到二分法,但是要注意到,我们只有3个手机!仔细想想,如果第一次二分后,第一个手机摔坏了,然后第二次二分又摔了一个手机,那么要确定手机的耐摔指数,就不能继续二分了,只能用最后一个手机从下往上摔了,不然如果再继续二分摔坏手机就确定不了耐摔指数了!所以我们得排除二分法!
那么我们该采取什么办法呢?
我们先不直接分析只有三个手机的情况,从只有一个手机的情况开始分析。
假设楼有n层可以测试,而且运气最差。
【只有一个手机时】__设楼层为i时,测试次数为time1[ i ]
此时,我们要确定手机的耐摔指数,只能从第一层往上测,直到手机摔坏或是到了最顶层,而又因为运气最差,所以肯定是需要一直测到最顶层的,不管在最顶层手机摔坏了没,测试次数都是n。即测试次数 times1[n] = n (要测多少层就摔多少次)
【只有两个手机时】__设楼层为i时,测试次数为time2[ i ]
我们既然有两个手机,那么第一个手机就可以用来测试。
如果第一个手机在第 k (1 <= k <= n) 层扔,那么分情况讨论:
综合1、2 及运气最差(这是为什么下面取最大值)可知:
temp_time = max(1+ times1[k-1] , 1+ times2[n-k] )
= 1 + max(times1[k-1] ,times2[n-k])
又题目中要求我们总是采用最佳策略,所以我们要遍历k的所有取值情况,取其中的最小值,
故temp_time = min(temp_time ,1 + max(times1[k-1] ,times2[n-k]) )
当遍历完k的所有取值情况后,用最小的temp_time给time2[n]赋值。
【只有三个手机时】__设楼层为i时,测试次数为time3[ i ]
同理只有两个手机时的情况,我们可以将第一个手机在第k(1 <= k <= n)层扔,然后分情况讨论。
写出式子就是temp_time = min(temp_time ,1 + max(times2[k-1] ,times3[n-k]) )
当遍历完k的所有取值情况后,用最小的temp_time给time3[n]赋值。
我们已经发现【只有一个手机时】的情况可以直接赋值,【只有两个手机时】和【只有三个手机时】的情况类似,那么就可以整合起来写,用二维数组times[4][1000]来存储,数组第一维表示手机数,第二维表示楼层数。整体逻辑是和前面分析的一样的,就不赘叙了。
#include
#include
#include
#include
#include
#include "string.h"
#include
using namespace std;
#define floor 1000
int times1[1005], times2[1005], times3[1005];//还有该层数待确定时,要扔手机的次数
int main()
{
//只有一个手机时
for (int i = 1; i <= floor; i++)楼层最高层数
times1[i] = i;//只有一个手机,所以每次都得从最后一层往上扔
//只有两个手机时
for (int i = 1; i <= floor; i++)//楼层最高层数
{
int min_time = INT_MAX;//需要的最小次数
for (int j = 1; j <= i; j++)//第一次扔的位置
1->第一次扔的次数 +
//(运气不好)取(“摔碎了”->手机数量-1 = 1,范围缩小到 j-1 层->times1[i-1][j-1],
// “没碎”->手机数量不变 = 2,范围缩小到 i-j 层->times2[i][i - j])两者最大值
min_time = min(min_time, 1 + max(times2[i - j], times1[j - 1]));
times2[i] = min_time;
}
//只有3个手机时
for (int i = 1; i <= floor; i++)//楼层最高层数
{
int min_time = INT_MAX;//需要的最小次数
for (int j = 1; j <= i; j++)//第一次扔的位置
1->第一次扔的次数 +
//(运气不好)取(“摔碎了”->手机数量-1 = 2,范围缩小到 j-1 层->times2[i-1][j-1],
// “没碎”->手机数量不变 = 3,范围缩小到 i-j 层->times3[i][i - j])两者最大值
min_time = min(min_time, 1 + max(times3[i - j], times2[j - 1]));
times3[i] = min_time;
}
cout << times3[floor]<
#include
#include
#include
#include
#include
#include "string.h"
#include
using namespace std;
#define floor 1000
#define phone_num 3
int times[4][1005];
int main()
{
for (int i = 1; i <= floor; i++)
times[1][i] = i;//初始化————只有一个手机的情况
for (int i = 2; i <= phone_num; i++)//手机总数
for (int j = 1; j <= floor; j++)//楼层最高层数
{
int min_time = INT_MAX;
for (int k = 1; k <= j; k++)//第一次扔手机时所在的层数
1->第一次扔的次数 +
//(运气不好)取(“摔碎了”->手机数量-1,范围缩小到 j-1 层->times[i-1][j-1],
// “没碎”->手机数量不变,范围缩小到 i-j 层->times[i][i - j])两者最大值
min_time = min(min_time, 1 + max(times[i - 1][k - 1], times[i][j - k]));
//取最小值是因为要取最优解法
times[i][j] = min_time;
}
cout << times[phone_num][floor] << endl;
return 0;
}