【蓝桥杯】【2018省赛】【填空题】测试次数

目录

题目

题目链接

提交结果截图

详细分析

易懂版:  

升级版:

带详细注释的源代码

易懂版:

升级版:


题目

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

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. 手机摔碎了,那么我们只剩下一个手机,这就回到了只有一个手机而楼层数为 k - 1的情况了。即测试次数(临时变量) temp_time = 1+ times1[k-1] (1是指的摔第一个手机的次数)
  2. 手机没摔碎,那么我们还是有两个手机,而且知道了1~k层都不用测试了,将测试范围缩小到了n - k。即测试次数 temp_time = 1+ times2[n-k] (times2[n-k] 肯定是比 times2[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)层扔,然后分情况讨论。

  1. 如果摔碎了,那么只剩下两个手机。
  2. 如果没摔碎,那么还是有三个手机。

写出式子就是temp_time  = min(temp_time ,1 + max(times2[k-1] ,times3[n-k]) )

当遍历完k的所有取值情况后,用最小的temp_time给time3[n]赋值。


升级版:

我们已经发现【只有一个手机时】的情况可以直接赋值,【只有两个手机时】和【只有三个手机时】的情况类似,那么就可以整合起来写,用二维数组times[4][1000]来存储,数组第一维表示手机数,第二维表示楼层数。整体逻辑是和前面分析的一样的,就不赘叙了。

带详细注释的源代码

易懂版:

#include <iostream>
#include <algorithm>
#include <climits>
#include <vector>
#include <cstdio>
#include "string.h"
#include <string>
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]<<endl;
    
    return 0;
}

升级版:

#include <iostream>
#include <algorithm>
#include <climits>
#include <vector>
#include <cstdio>
#include "string.h"
#include <string>
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;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值