测试次数(蓝桥杯)

前言

在刷题的时候无意中发现这么一道题目,乍一看还挺简单的,没想到没那么简单,有点意思,记录分享一下,顺便水一篇博文~
最近又犯贱了,状态有点乱,文章质量不好见谅!

题目

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

卡点

这道题目怎么说呢,一开始我认真看题目,因为这个是19年B组JAVA蓝桥杯的题目,是第四题,前面都比较简单,包括第五题就是个线性时间选择填空嘛,所以当时随便想了一下然后写了一下,然后发现答案不对。之后查了一下,搞了半天没看懂人家是怎么推出来的,最后还是自己打表,打出来了。

这道题目我当时为什么没有反应过来,想错了,主要还是因为这个语文理解比较差,每太搞懂他题目的意思。
这里的话我也是转述一下,就是 叫你摔手机 去测试手机的抗摔值,第一层摔下去没碎那么那个值最少为1,第二层没碎再+1,直到手机摔碎了,测出耐摔值。现在假设有三个手机,问,三台手机运气不好的情况下摔多少次才能出结果。

这题比较可恶的就是这个手机到底是怎么个摔发不好想,如果知道他是怎么个摔法之后,其实就能够直接很快地出想法,我也是这里卡住了,没搞懂这个怎么个摔法,然后还运气最差。

不过这里关于dp的暗示倒是挺明显的,一个是“最”这个字眼,还有就是题目相当于直接告诉你了影响dp的因素,层数和手机数。所以这块dp的话很好想 首先value自然是我们要求的内容,然后dp[i][j] 其中 i 表示楼层,j 表示手机。当然你也可以反过来,只是我比较喜欢这样。

打表

这个时候的话我们好好好思考一下这个手机是怎个摔法了。这块,我们先打个表
在这里插入图片描述
这个是第一点,我们很容易想到。

接下来就是有两个手机的情况。

如果是楼层只有1层的话,那么我两台手机也是摔1次,如果是两层的话,我可以直接在第二层摔,坏了我就到第一层测试,没坏,我就直接测出来了,那么我就只需要1次。或者说,我也是继续从一层开始测,然后测到二楼。他要最大的,那么此时我也给他个2
在这里插入图片描述
那如果有2台手机,然后有3,4,5层。如果是三层,显然先直接在三层摔,碎了,1次,没碎去第二次,剩下一部手机,那么此时我不可能从二层直接摔,我只能从1开始,那就是1台手机测2层最多要多少,显然此时是2 然后加上先前那一次。所以是3

那么如果两台手机4层呢,此时假设我继续直接从四层开始丢,那么按照咱们的假设,大概最坏也是4次,那如果我是从3层开始丢呢。

所以这里我们可以总结出一个表,对于两台手机,从不同楼层往外丢,然后测出来的最好和最坏的次数。
其中 好,碎 是指当前层有没有摔坏
在这里插入图片描述

所以这个时候我们发现如果按照最有策略,然后运气最差的情况下,我们不能直接从顶楼开始丢,但是显然按照咱们的常识一开始直接从高处丢要比直接从第一层开始要好,但是显然我们不能直接主观,所以这个时候我们需要选择一个合适的策略。

问题转化

那么这个时候我们已经确定了,这个问题有两个点要处理,一个是确定dp,还有一个是确定策略也就是第几层开始。

那么这里问题显然就是问你在最好的策略下面,要耗费的做多次数,也就是在咱们,下面这张表里面
最多最小的。然后这个每一层的这个最多,又是和手机在当前层碎没碎决定的。如果没有碎掉
那么就是 dp[n-i][j] i 是层数,i是手机个数。如果坏了就是 1+dp[i-1][j-1] 然后再确定出最好的策略,把对应的“最多” 填进去就ok了

在这里插入图片描述

编码

这么说可能有点绕了,接下来看代码你就直接明白了。

public class 测试次数 {
    
    
    static int N = 1000;
    static int M = 3;
    static int[][] dp = new int[N+1][M+1];
    public static void main(String[] args) {
    
    
        //初始化,第一台手机
        for (int i=1;i<N;i++){
    
    
            dp[i][1] = i;
        }

        //中间状态
        for (int i=2;i<=3;i++){
    
    
            for (int j=1;j<=1000;j++){
    
    
                //选择出最好的方案
                int min_val = Integer.MAX_VALUE;
                for(int k=1;k<=j;k++){
    
    
                    int max = Math.max(1 + dp[j - k][i], (dp[k - 1][i - 1])+1);
                    min_val = Math.min(max, min_val);
                }
                dp[j][i] = min_val;
            }
        }

        System.out.println(dp[N][M]);
    }
}

总结

这题的有意思的地方就是那个手机怎么个摔法,搞清楚了这个中间过程其实很容易就能够搞出来。这个也是比较有意思的地方。

猜你喜欢

转载自blog.csdn.net/FUTEROX/article/details/123669007