zoukankan      html  css  js  c++  java
  • 测试次数

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

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

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

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

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

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

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

    答案:

    这道题当初理解错了,看了别人博客发现其实好多人都理解错了题意,意思是给三个手机,前两个都摔碎后没有测出指数,最后一个碎了才测出来了,显然要知道耐摔指数,需要是在第i层摔不碎,第i + 1层摔碎了,可以确定耐摔指数为i,或者第n层没摔坏和第1层就摔坏了。显然我们每个手机都应该从低层开始摔,如果上来就是从高层,直接摔碎了,鬼知道耐摔指数是多少,如果是一个手机,就得按照1,2,3,4……的顺序摔,直到测出来,如果是两个手机,那么用第一个手机测试的时候就不用每次加一层来摔了,增量可以大一点,设这个增量为k,第一次在第k层摔,第二次2k。。这样的,直到第ik摔碎了,那么范围缩小为(i-1)k到ik之间,然后开始测试第二个手机,第二个手机是从(i-1)k+1开始的,每次只能加1,才能测出来,实际上这个k是不好取的,看别人题解也是看了半天,dp[i][j]表示用i部手机,共j层最少测试多少次,显然dp[i][j]是取最小值的,先让dp[i][j] = dp[i][j - 1] + 1;显然这是dp[i][j]的最大值,dp[i][j - 1]表示j-1层用i部手机测出来的最小次数,无非多摔一次可以测出来j层的,然后找他的最小值,根据不同的k,dp[i][j] = min(dp[i][j],max(dp[i][j - k],dp[i - 1][k - 1]) + 1);dp[i][j-k]表示手机数量一样,每次摔完不碎就摔+k层的,每次加k,dp[i - 1][k - 1]表示当前k为基础,摔碎了,那么就需要用剩下的手机去测试k - 1层的就好了,因为范围缩小到k - 1层了。

    代码:

    #include <iostream>
    using namespace std;
    int dp[10][1001];
    int main() {
        int stair_num,phone_num;
        cin>>stair_num>>phone_num;
        for(int i = 1;i <= stair_num;i ++) {
            dp[1][i] = i;
        }
        for(int i = 2;i <= phone_num;i ++) {
            for(int j = 1;j <= stair_num;j ++) {
                dp[i][j] = dp[i][j - 1] + 1;
                for(int k = 2;k < j;k ++) {
                    dp[i][j] = min(dp[i][j],max(dp[i][j - k],dp[i - 1][k - 1]) + 1);
                }
            }
        }
        cout<<dp[phone_num][stair_num];
        return 0;
    }

    大佬的思维真是让人望尘莫及,另外是用数学转化思想做,把问题转化为,给出三个手机,k次测试最多可以测试多少层,测试层数>=1000的最小k就是答案,一部手机k次测试最多也就是k层,然后就是两部手机,加入我们用一部手机按照k大小的区间不断增加层数测试,每次加k层,直到摔碎了,范围缩小到k - 1,一部手机测试k - 1层,最少要k - 1次,现在我们要直到测试k次最多可以解决总层数多少层的问题,不管怎么样,组后一次都是区间为1的,前面的都是>=1的,要保证测试k次之间都是没有纰漏的也就是说如果第一次测试的是k大小的区间,第二次测试的如果还是k大小的区间,最终范围缩小为k - 1,但是我们已经测试了不止一次,最后k - 1的区间我们可能并不能测试出正确的结果,所以第一次是大小为k的区间,第二次k - 1,最后一次就是大小为1,总的就是(k + 1) * k / 2层,保证它>=1000的k为45,那么如果是三部手机的话,其实道理也是一样的,k-1次机会最多可以测试k(k-1)/2层楼,所以第一次在k(k-1)/2+1层楼,如果第一次就碎了,范围缩小为k(k-1)/2,正好是k-1次机会可以解决,第一次如果第一部手机不碎,第二次在此基础上增加(k-1)(k-2)/2+1层楼,一次机会就是可以解决2*(2-1)/2=1,所以倒数第二次加2*(2-1)/2+1,最后一次加1*(1-1)/2+1,求和i*(i-1)/2+1(1<=i<=k),得(k^3+5k)/6>=1000,k=19。

  • 相关阅读:
    android view生命周期
    ViewPager 滑动页(四)
    android 中如何获取camera当前状态
    Android LayoutInflater原理分析,带你一步步深入了解View(一)
    仿Twitter登陆移动背景效果
    Android应用性能优化之使用SQLiteStatement优化SQLite操作
    GreenDao官方文档翻译(下)
    高级IO
    linux信号
    LINUX进程
  • 原文地址:https://www.cnblogs.com/8023spz/p/10585356.html
Copyright © 2011-2022 走看看