入门级动态规划:2018年第九届蓝桥杯省赛B组第四题—测试次数( 摔手机 )

2023-10-31

目录

 

——下面列出用动态规划如何解决此问题——

①计算若干层楼用若干部手机最少需要摔多少次

②计算用若干部手机摔若干次最多可以确定多少层楼


原题描述:

        x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
        x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
        如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n

        为了减少测试次数,从每个厂家抽样3部手机参加测试。
        某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
        请填写这个最多测试次数。

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

        先把答案写在前面 19


当初没有注意到题目中的关键,只提供3部手机供你测试摔手机。直接一个二分法lg1000/lg2<10,交了个10,于是华丽丽的错掉了,二分法虽然可以在最短次数测到最坏可能性,但是致命的是它每次直接从中间高度摔手机,手机很有可能摔坏,如果想要用二分法摔出耐率指数是0的手机,那么足足需要摔坏10部手机!

还有要说明的是,假设手机个数是无限的可以采用二分法。

用二分法摔手机必须要确定耐摔指数 0~1000 ( 目标楼层数 ),因为耐率指数可以是0。当我们只有一层楼的时候,是需要摔一次才能确定耐摔指数是 0 还是 1 ,同理只有两层楼的时候需要摔两次才可以,并不是只需要1次( lg2 / lg2 = 1 ),因为排除了一个数后最后一个数也是需要摔的!

这个陷阱对于二分1000这个高度没什么,但如果是512层,二分法摔手机就得是10次了( lg513/lg2 ),而不是9次( lg512 / lg2 )。


        那如果只给了一部手机,怎么测出耐率指数呢?只好从1层开始摔,摔坏了就是(当前层数-1)的耐率指数。假如是两部手机呢?我一开始的想法是对1000进行分块,先用第一部手机摔出目标层数在哪一个小块里,然后再用第二部手机从那个小块最低层一层一层往上摔,直到确认为止。按照这个想法1000层需要分成 a*b*c 三个手机分别负责一个变量,最后就能确认目标层数。

        为了给自己的歪理加个公式增强点可信度,我想到了高中的基本不等式……3√(a*b*c)<=(a+b+c)/3 ,设a*b*c是1000,这么一算a+b+c最小值不就是30吗,a=b=c=10的时候成立。这么看来最难摔到的层数应该就是1000层了,第一部手机摔9次才能确定目标层数在901~1000( 摔101、201…901 ),然后再摔上9次才能确定目标层数在991~1000( 摔911、921…991 ),再摔上9次才能确定是1000( 摔992、993…1000 )确定出目标层数1000。可能有疑问为什么这里不考虑1了呢,因为我们采用的是自底向上排查,虽然1~10的范围必须要摔上10次才能确定每个值,但是1~10的范围只需要摔101和11就能确定下来( 两次 ),所以我们不考虑它会额外产生次数。因此这种方法摔手机27次能用三部手机摔出目标楼层!

        是不是有点太多了?!!

        ****显然是的,虽说分块分的很合理看上去无懈可击,但是这是建立在分同等长度块的前提下的。找到每个楼层的次数严重不均匀,因为是自底向上的摔,位于前面的楼层可以在短短几次就能确定范围,排在后面的楼层却需要许多次才能确定下范围,这无疑是不公平的,只有位于后面的楼层才会用最大次数摔后确定下来。

        那么为了均衡,把前面的块范围加大,后面块的范围缩小。这样前面的块很快能确定,但是它内部需要很多次才能确定到底是哪一个,而后面的块很多次才能确定但内部很小,因而很快可以确定是哪一个!完美的解决方法……

        如果是20层楼,我们用 2 部手机手机摔。那么最后一个确定的块范围定为1,那么5+5+4+3+2+1 这么划分是最合理的,在每一个块的最后一层扔第一部手机( 这是为了照顾第一层 ),确认下来目标楼层在哪个块之后在块内部用第二部手机扔。第一个块扔一次可以确定,但是内部需要4次;第二个块需要2次确定范围,内部需要4次确定;最后一个块需要摔上5次才能确定,但是内部摔上1次就可以。所以最后的结果应该是6次。这种分法恰好解决了必须要摔1楼的坑!最后一个块必摔一次,前面的块摔长度减一次。

        那当我们有三部手机呢,更深一层的分块,也就是说把全部楼层划分后用两部摔出每个块的内部……继续根据每个块的内部次数分配楼层!!这么来手算就太费劲了,现在看来显然是个动态规划问题了,分解成用 cnt 部手机可以在 ind 楼层最少摔多少次可以确定全部楼层?在一部手机的时候肯定是从1~1000了,一层一层确认。

以上内容分析了是如何得到最小摔手机次数的,核心在于大于两部手机时需要分块后摔第2~n部手机,且块内层数必须大于等于1,这样最后一部手机才有利用价值。


——下面列出用动态规划如何解决此问题——


①计算若干层楼用若干部手机最少需要摔多少次

1.设ind为当前层数,cnt为当前拥有手机个数,dp[ind][cnt]为此时最少摔多少次。

2.cnt=1时,没有任何花里胡哨,从低往高一层一层摔。

dp[ind][1]=ind

3.cnt>=2时

先看一个小例子,ind=4,cnt=2时,如何计算?目标当然是得到dp[4][2]的值。

—>用表格列出得到过程,cnt=1的情况先写出。

 

ind=1

ind=2

ind=3

ind=4

cnt=1

1

2

3

4

cnt=2

 

 

 

 

 

 

 

 

ind=1,cnt=2时,dp[1][2]显然也是1,一层楼摔一次足矣。

ind=2,cnt=2时,2层楼,摔一次肯定不够,必须摔两次。

 

ind=1

ind=2

ind=3

ind=4

cnt=1

1

2

3

4

cnt=2

1

2

 

 

 

 

 

 

ind=3的时候呢??

首先可以确定的是,用2层楼确定的最小次数+1,多摔上一次肯定能确定出3层楼最少用多少次。也就是说dp[3][2]最大值就是dp[2][2]+1  ,只需要确定的能不能等于dp[2][2]……

****有三层楼,手中拿出一部手机,可以去1~3层摔对不对,一开始说了那么多怎么个分块法得到最小次数, cnt 又大于1,肯定是需要分块后摔手机的。分块最小是块中有一层,这样下一部手机才不会没有用处。

于是乎拿出一部手机摔的层数肯定是(1+1)~(3-1)层(2层)

在2层这部手机摔碎了,那么就需要用剩下的cnt-1部手机来确定1层(2-1层~1层,共一层)手机是否会摔碎;(dp[1][1]+1)

在2层这部手机没有摔碎,那么就需要用cnt部手机来确定3层(2+1层~最高层,共一层)手机是否会摔碎;(dp[1][2]+1)

+1的意义是在2层摔的这部手机,是摔了一次的。

摔碎和没摔碎这两种情况的最大值就是在当前楼层摔手机可以得到的最小摔手机次数。

现在我们看看分析得到的结果

(1)    dp[3][2]<=dp[2][2]+1

(2)    dp[3][2]>=Max( dp[3-k][2]+1 , dp[k-1][1]+1 )

k大于1,小于ind(此处k只能等于2)。

我们需要的当然是最小值,即==>     dp[3][2]=Max( dp[3-k][2]+1 , dp[k-1][1]+1  )    =  2

 

ind=1

ind=2

ind=3

ind=4

cnt=1

1

2

3

4

cnt=2

1

2

2

 

 

 

 

 

同理分析ind=4,cnt=2时。

最大值:dp[3][2]+1 = 3

最小值: k=2,Max( dp[2][2]+1 ,dp[1][1]+1 ) = 3

               k=3,Max( dp[1][2]+1 ,dp[2][1]+1 )  = 3

dp[4][2] = 3

 

ind=1

ind=2

ind=3

ind=4

cnt=1

1

2

3

4

cnt=2

1

2

2

3

 

 

 

 

完成!四层楼用两部手机至少需要摔 dp[4][2] = 3 次。

总结以上,dp[ind][cnt]=Min( dp[k-1][cnt-1] ,dp[ind-k][cnt] ) +1     1 < k < ind

还有个毛病是:ind=1、2的时候,k是不存在的,这时候采用最大值 dp[ind-1][cnt]+1 即可,初始化 dp[0][cnt]=0

综合起来采用:dp[ind][cnt] = Min( 1+dp[ind-1][cnt] , 1+Max( dp[k-1][cnt-1] , dp[ind-k][cnt] )     1 < k < ind

#include<stdio.h>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
int dp[1005][50];
int main(int argc, char* argv[])
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        dp[i][1]=i;
    for (int cnt=2;cnt<=m;cnt++)
    {
        for (int ind=1;ind<=n;ind++)
        {
            dp[ind][cnt]=1+dp[ind-1][cnt];
            for (int k=2;k<ind;k++)
                dp[ind][cnt]=Min(dp[ind][cnt],1+Max(dp[k-1][cnt-1],dp[ind-k][cnt]));
        }
    }
    printf("%d\n",dp[n][m]);
    return 0;
}

②计算用若干部手机摔若干次最多可以确定多少层楼

顺着逐级分块摔每部手机的思路,得到了第一个较为直观的做法。这次反过来,在确定手机数和摔手机次数后,计算一下能确定出的最大楼层数,然后遍历目标手机数下达到目标楼层的最小摔手机次数是多少。

和第一种做法同样的思路,摔一部手机会让楼层分为两部分,下面的楼层需要手机数 - 1 后确定,上面的楼层部分手机数不变确定,我们不知道该在哪个楼层将当前楼层分为两部分,所以我们遍历 来确定。

上面那个思路是否可以考虑将:变量由手机数量和楼层数改为手机数量和摔手机次数,最小摔手机次数这个因变量改为可确定楼层最大值呢?

这次已知摔手机次数 i 和手机数量 jdp[ i ][ j ] 为其可确定楼层最大值。当前可确定的最多楼层数就会是摔手机次数 i - 1 ,手机数量 jj - 1 下的可确定楼层数最大值之和,也不要忘了每次摔手机都会确定所摔楼层,每摔一部至少可以确定一层,所以推出:

dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i - 1 ][ j - 1 ] + 1

确定目标楼层 n 最多需要摔多少次手机呢?那肯定是手机只有一部的时候,最多需要 n 次才能确定目标楼层。我们设定摔手机次数 i 1n 遍历,计算当前次数下手机数为指定值 m 时的 dp[ i ][ m ] 是否大于等于目标楼层n,这样计算出最小的摔手机次数后输出即可。

这种做法显然是比做法①快不少的,减少了遍历寻找最佳分层点的部分,是更为优秀的~~

#include <stdio.h>
int dp[1005][50];
int main(int argc, char *argv[])
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
            dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] + 1;
        if (dp[i][m] >= n)
        {
            printf("%d\n", i);
            break;
        }
    }
    return 0;
}

两种做法的C代码均给出 -> 输入 1000 3 即可得到结果 19

 

END

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

入门级动态规划:2018年第九届蓝桥杯省赛B组第四题—测试次数( 摔手机 ) 的相关文章

  • 蓝桥杯青少组python:第十三届省赛第一场

    选择题 1 下列二进制中最大数是 A 110 B 1010 C 1100 D 1001 2 以下方法 不是对文件读操作的是 A readline B readlines C readtext D read 3 以下对turtle库中函数描述
  • 通过int 关系运算符来 比较两个 float 变量的大小

    include
  • openGL之API学习(一九四)glGenTextures glActiveTexture

    glGenTextures产生的是一个比较小的整数id 纹理单元名 glActiveTexture激活的是纹理单元号 GL TEXTUREi 它们二者的关系为GL TEXTUREi GL TEXTURE0 id glBindTexture使
  • 第五届蓝桥杯—— 基础练习:数列特征

    问题描述 给出n个数 找出这n个数的最大值 最小值 和 输入格式 第一行为整数n 表示数的个数 第二行有n个数 为给定的n个数 每个数的绝对值都小于10000 输出格式 输出三行 每行一个整数 第一行表示这些数中的最大值 第二行表示这些数中
  • 蓝桥杯---貌似化学---逆矩阵

    试题 算法训练 貌似化学 资源限制 时间限制 1 0s 内存限制 256 0MB 问题描述 现在有a b c三种原料 如果他们按x y z混合 就能产生一种神奇的物品d 当然不一定只产生一份d 但a b c的最简比一定是x y z 现在给你
  • openGL之API学习(一九三)glGenTextures

    生成纹理单元名 单元名不一定是连续的 但是没有使用的 单元名是相对GL TEXTURE0的 对于单元名1 其实是GL TEXTURE0 1 glGenTextures产生的是一个比较小的整数id 纹理单元名 glActiveTexture激
  • 蓝桥杯.卡片(模拟)

    Question Result 3181 Solve 直接模拟暴力 初始化卡片数量为2021 去模拟拼数的过程 注意点的话 我是先去判断卡片还有没有 再去减一 所以输出结果也有一个减一 因为一旦说卡片没有了 就意味着当前这个数字拼不成了 C
  • 【顺序表图书管理】

    一 实验目的 掌握顺序存储的线性表的创建 查找 插入 删除和输出操作 二 实验内容 实现一个存放图书信息的顺序表 三 实验要求 图书的基本信息有图书编号 例如 1 2 3 4等 书名和价格等 对图书的顺序表进行查找 插入 删除和输出操作 3
  • 蓝桥杯:斐波那契数列最大公约数

    题目表示的很明确 要用两个算法 斐波那契数列是很经典的dp问题 最大公约数是很经典的辗转相除法 从而我理所应当的就定义一个数组存放斐波那契数列 long long int F 2021 0 F 1 1 F 2 1 for int i 3 i
  • 【算法竞赛】Python快速入门指南

    该指南由GPT4编写 用于快速入门蓝桥杯Python组 当然 仅限入门而已 本指南由GPT 4生成 我只是负责引导 并对内容进行整理和补充 一直以来我都是使用C 作为算法竞赛语言 但是奈何C 组太卷 自己又太菜 于是另谋他路 Prompt模
  • 第十四届蓝桥杯程序设计C++B组 (详细图解+保姆级注释)

    0 写在前面 本届CB组题目难度较往年整体提升了一些 考察知识点全面 题目质量很高 推荐备赛蓝桥杯或感兴趣的同学深入研究本套题 废话不多说 直接上干货 一 冶炼金属 签到题难度 考察数论分块知识or二分 有部分同学可能知道下取整的定义 但是
  • 1093: 数1的个数

    存限制 128 MB 题目描述 给定一个十进制正整数n 1 n 10000 写下从1到n的所有整数 然后数一下其中出现的数字 1 的个数 例如当n 2时 写下1 2 这样只出现了1个 1 当n 12时 写下1 2 3 4 5 6 7 8 9
  • 动态规划之多重背包模型

    前置知识 01背包问题 动态规划之01背包模型 如何何何的博客 CSDN博客 完全背包问题 动态规划之完全背包模型 如何何何的博客 CSDN博客 多重背包问题 给定一个有一定容量的背包 和 n 个物品 每个物品有 si 件 每个物品有其对应
  • 蓝桥杯第23天(Python)(疯狂刷题第6天)

    题型 1 思维题 杂题 数学公式 分析题意 找规律 2 BFS DFS 广搜 递归实现 深搜 deque实现 3 简单数论 模 素数 只需要判断到 int sqrt n 1 gcd lcm 快速幂 位运算移位操作 大数分解 分解为质数的乘积
  • 第14届蓝桥杯C++B组省赛

    文章目录 A 日期统计 B 01 串的熵 C 冶炼金属 D 飞机降落 E 接龙数列 F 岛屿个数 G 子串简写 H 整数删除 I 景区导游 J 砍树 今年比去年难好多 Update 2023 4 10 反转了 炼金二分没写错 可以AC了 U
  • 蓝桥杯python,acwimg,备赛笔记

    目录 一 python基本的语法 二 掌握python标准库 三 acwimg算法课 四 注意事项 四 刷题 五 用python刷算法题中的小技巧 六 完整代码 一 python基本的语法 学到面向对象就差不多了 不需要太深入学习面向对象后
  • [蓝桥杯 2014 省 A] 波动数列

    题目链接 蓝桥杯 2014 省 A 波动数列 题目描述 观察这个数列 1 3 0 2
  • AtCoder Beginner Contest 332 G. Not Too Many Balls(最大流转最小割 dp)

    题目 n n lt 500 种球 第i种有ai 0 lt ai lt 1e12 个球 m m lt 5e5 个盒子 第j个能放bj 0 lt bj lt 1e12 个球 特别地 第j个盒子最多能放i j个第i种球 求m个盒子能放的最多的球的
  • 字符串处理-第11届蓝桥杯省赛Python真题精选

    导读 超平老师的Scratch蓝桥杯真题解读系列在推出之后 受到了广大老师和家长的好评 非常感谢各位的认可和厚爱 作为回馈 超平老师计划推出 Python 蓝桥杯真题解析100讲 这是解读系列的第26讲 字符串处理 本题是2020年6月20
  • 如何查看崩溃日志

    目录 描述 思路 查看ipa包崩溃日志 简单查看手机崩溃信息几种方式 方式1 手机设置查看崩溃日志 方式2 Xocde工具 方式3 第三方软件克魔助手 环境配置 实时日志 奔溃日志分析 方式四 控制台资源库 线上崩溃日志 线上监听crash

随机推荐

  • sqli-labs(27)

    0X01 先查询闭合 id 1 报错 id 1 正确 知道是 的闭合语句 0X02那么开始我们的注入之旅 空格过滤了 尝试一下 0a绕过 也被过滤了 那么用and 1 1构造闭合 id 1 1 1 显示正确 我们来爆一下数据名称 哦豁 un
  • 产品经理工作积累(1)

    相比较做技术工作的人来说 做产品工作的更倾向于软能力 而这种软能力体现在个人的产品思想上 更或者说做产品的思维或理念 做产品除了本身的产品设计能力外 还有一点就是产品的思想 同一种产品不太的产品做出来后产品形态都会不同 特别是对于一些有独特
  • 在 Shell 脚本中调用另一个 Shell 脚本的三种方式

    先来说一下主要以下有几种方式 fork 如果脚本有执行权限的话 path to foo sh 如果没有 sh path to foo sh exec exec path to foo sh source source path to foo
  • android 反编译方法、工具介绍

    网上有很多的反编译文章 个人认为写的比较好的文章有 APK反编译得工具总结 转载 hayhx 博客园 我也是参考其文章来的 本人写此文章目的 以及反编译运用场景 主要有以下几方面 记录反编译的方法 方便自己用的时候比较方便 起到记录的作用
  • python词频统计_Python中文词频统计

    1 下载一长篇中文小说 2 从文件读取待分析文本 3 安装并使用jieba进行中文分词 pip install jieba import jieba ljieba lcut text import jieba txt open r piao
  • async 和 await

    async async是一个加在函数前面的修饰符 被async修饰的函数会默认返回一个promise对象 可以使用then方法添加回调函数 返回的promise对象的结果是由async函数执行的返回值的结果来决定的 1 当async函数内部
  • 一步步教你用 WebVR 实现虚拟现实游戏

    翻译 疯狂的技术宅 www smashingmagazine com 2018 11 vir 在本教程中 我们将创建三维对象并为它们添加简单的交互 此外 你还可以学到如何在客户端和服务器之间建立简单的消息传递系统 虚拟现实 VR 是一种依赖
  • 说说HashMap的扩容机制

    HashMap的扩容机制 HashMap的数据结构 HashMap几个重要的元素 HashMap的扩容过程 1 为什么扩容 2 什么时候进行扩容 3 怎么扩容 HashMap的数据结构 JDK1 8为例 如图 先知道三个概念 table 存
  • Vmware安装Ubuntu出现 unable to find a medium containing a live file system

    一 前言 由于未知的原因 使用Vmware安装Ubuntu的时候 总是遇到奇怪的问题 忘记截图了 大致是 unable to find a medium containing a live file system 找了几个帖子 参考1 参考
  • ajax 调用node,Node.js 远程调用 方法大全

    关于Node js 远程调用 远程调用 简称 RPC 主要是指服务器或集群之间对处理过程的调用 通过远程调用可以打通不同系统之间的数据与功能 或是抽离与建立公共的逻辑统一提供服务 远程调用的两端也称为远程调用的客户端与服务端 一般是多对多的
  • 借助模糊逻辑将文化算法与和谐搜索相结合进行学习——文化和谐学习算法(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 Matlab代码实现 4 参考文献 1 概述 文化和谐学习算法 创建于 18 Jan 2
  • 剑指 Offer 24. 反转链表

    定义一个函数 输入一个链表的头节点 反转该链表并输出反转后链表的头节点 示例 输入 1 gt 2 gt 3 gt 4 gt 5 gt NULL 输出 5 gt 4 gt 3 gt 2 gt 1 gt NULL 代码 Definition f
  • exchange 系统管理器 服务器,在“exchange系统管理器”安全里有个receive as是什么权限?谢谢...

    您好 用Visual Basic访问Microsoft Exchange和Outlook的数据 想通过Access中的Visual Basic for Applications VBA 和数据访问对象 DAO 的方法和对象来连接和导入来自E
  • 故事板(Storyboard)

    1 使用Storyboard完成各项常见功能 1 1 问题 故事板Storyboard是IOS5开始引入的一个新的系统 将多个视图文件 类似xib文件 集中到一个单独的可视化工作区间 负责创建和管理所有的界面及界面间的跳转 每一个Story
  • 【Log日志】springboot项目中集成Log日志详解

    springboot项目中集成Log日志详解 一 Log日志介绍 1 Log 日志组件主要作用及用途 2 日志的级别Level 级别控制 3 日志的输出Import 3 1 快速使用 3 2 日志文件输出 3 3 自定义配置 4 Sprin
  • 微派三轮面试总结

    三轮技术面 面试周期 2023 6 19 2023 6 26 目录 一面 1 介绍一下自己的项目 2 Vue2中父子组件的声明周期执行顺序是怎么样的 3 computed和watch的区别 4 Vue路由中包含两种模式 hash和histo
  • 在windows中使用scp命令

    windows自带scp命令 上传文件 使用方法 scp 源文件路径 账户 地址 目的路径 scp C Users zbh Desktop 1 txt lucas 192 168 11 150 home lucas 然后输入密码即可 下载文
  • React18的useEffect会执行两次

    React18的useEffect会执行两次 useeffect执行两次 翼晗的博客 CSDN博客
  • ubuntu20.04开启SSH远程登录

    默认情况下 首次安装Ubuntu时 不允许通过SSH进行远程访问 以root 用户或具有sudo特权的用户执行以下步骤 以在Ubuntu系统上安装并启用SSH 1 打开终端并安装openssh server软件包 sudo apt upda
  • 入门级动态规划:2018年第九届蓝桥杯省赛B组第四题—测试次数( 摔手机 )

    目录 下面列出用动态规划如何解决此问题 计算若干层楼用若干部手机最少需要摔多少次 计算用若干部手机摔若干次最多可以确定多少层楼 原题描述 x星球的居民脾气不太好 但好在他们生气的时候唯一的异常举动是 摔手机 各大厂商也就纷纷推出各种耐摔型手