2018年蓝桥杯C/C++ B组省赛 试题D:测试次数题解


题目描述

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

x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。
塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?

输出

输出一个整数表示答案

解题思路

刚拿到题目时,我以为这道题目用二分来写,但是需要考虑到二分适用于有无数台手机给我们去尝试,而这道题目的手机数量是有限的。

这是一道典型的dp问题。

众所周知dp问题的关键在于填表,我们认为dp[i][j]表示 i 为使用到了几个手机,j 表示验证了几层,那么dp[i][j]的结果为测试了几次。

那么我们来考虑:

1、当只有一部手机时,最坏情况下我们需要从第 1 层一直测试到第 j 层楼,那么一共测试 j 次,dp[1][j] = j

2、当拥有两部或两部以上手机时,这时我们需要考虑最优策略

当前我们在第 k 层测试,用到第 i 部手机时,测试会出现两种情况

第k层示意图

a.摔坏:如果在第 k 层摔坏了,那么我们只需要用剩下的 i - 1 部手机去测试剩下的k - 1层楼,即dp[i - 1][k - 1]

b.未摔坏:如果在第 k 层没有摔坏,那么我们只需要用 i 部手机去测试剩下的n - k层楼,即dp[i][n - k]

因为在这个测试过程中,我要保证运气最坏,因此dp[i][k] = max(dp[i - 1][k - 1], dp[i][n - k]) + 1

其中:

+1 是指 无论当前这次测试摔坏、没摔坏,我都进行了一次测试

max 的目的 是要在测试过程中保证运气最坏,即最坏情况

  • 状态转移方程:dp[i][j] = min(d[i][j], max(dp[i - 1][k - 1], dp[i][n - k]) + 1)

  • 其中min是时刻要保证最优策略

解题代码

//
//  main.cpp
//  2018lanqiao-d
//
//  Created by 陈洋 on 2020/10/11.
//  Copyright © 2020 陈洋. All rights reserved.
//

#include <iostream>
using namespace std;

int dp[5][1010];
int main(int argc, const char * argv[]) {
    int n = 3, m = 1000;
    
    for(int i = 1; i <= m; i++)
        dp[1][i] = i;   //当只有一个手机,就从1楼试到m楼,最坏情况是m
    
    for(int i = 2; i <= n; i++){    //从两部手机开始循环,第i部手机
        for(int j = 1; j <= m; j++){    //j表示有j层楼
            dp[i][j] = dp[i][j - 1] + 1;    //最坏情况下每一层楼都试一次
            for(int k = 2; k < j; k++){
                /*
                 dp[i][j - k]代表当前这个手机在第k层没有摔坏,那么就看剩下的j - k层楼
                 dp[i - 1][k - 1]代表当前这个手机在第k层摔坏了,那么就看i - 1个手机在 k - 1层测试。
                 因为我用手机测试第k层时,如果摔坏了就说明在向下的k - 1层,如果没有摔坏则说明在向上的j - k层
                 不管测试结果如何,最后都摔了一次,则尾部 +1
                 */
                int temp = max(dp[i][j - k], dp[i - 1][k - 1]) + 1;
                dp[i][j] = min(dp[i][j] , temp);    //找到最优的k
            }
        }
    }
    
    cout << dp[3][1000] << endl;
    
    return 0;
}

参考:2018蓝桥杯B组第4题:测试次数

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

省下洗发水钱买书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值