楼层仍鸡蛋问题

前言

大一的时候蓝桥杯省赛遇到过(作为非编程题的压轴题),这次看的别人的面经也多次出现,就写篇博文总结一下。

题目

有一栋楼共100层,一个鸡蛋从第N层及以上的楼层落下来会摔破, 在第N层以下的楼层落下不会摔破。给你2个鸡蛋,设计方案找出N,并且保证在最坏情况下,最小化鸡蛋下落的次数。

解析

无脑二分法(最多人想到的伪解法)

当时省赛没注意审题,就想的这种方法,首先需要确定的是,在最坏的情况下,求最小化尝试次数,所以肯定不是无脑二分那么简单了,例如,你第一次仍第50层,碎了如果你再选择二分,直接到25层又碎的话,两个鸡蛋就都没了,接下来你咋试啊?所以你接下来只能从1层到49层一个一个试了,最终尝试次数为50次。

假设法

首先,假设答案,也就是最小尝试次数为x,此时从第x层开始仍,有两种情况:

  • 碎了,那么只能从1到x-1一个一个试了,总结果为x次,符合。
  • 没碎,那么直接把第1到x层抛弃掉,当作不存在(因为鸡蛋不会在这范围内碎掉),我们把第x+1层当成第1层,尝试次数为x-1(因为刚刚仍了1次,最小尝试次数减1),此时就从第x-1层(真实层数为x+x-1)开始仍,同样又会出现两种情况:
  • 第二次碎了,则是从第1层到第x-2层开始仍 ,总尝试次数同样是x
  • 第二次没碎,还是之前原理,这次从x-2层开始,以此类推,一直扔到最后一层或碎了为止。

最终结果就是\(x+(x-1)+(x-2)...+1 = 100\),解得\(x = 14\)

题目升级版本

楼层M,鸡蛋数N,求最坏情况下的最小次数。

动态规划法

理解了上面的假设法,再学过动态规划的话,这里应该就问题不大了。
状态转移方程如下:
\[f[m][n] = min(f[m][n],1+max(f[k-1][n-1],f[m-k][n]),k\in[1,m-1])\]
解释:当有n个鸡蛋时,所需尝试的楼层数为m,此时将鸡蛋仍在第k层,则有两种情况

  • 碎了,那么接下来只需要尝试1到k-1层,鸡蛋数为n-1,此时问题不就转化成了楼层数k-1,鸡蛋数n-1,求最坏情况下的最小次数吗?
  • 没碎,那么直接把第1到k层抛弃掉,只需要尝试第k+1到m层,鸡蛋没碎,所以仍为n,此时问题不就转化成了楼层数m-k,鸡蛋数n,求最坏情况下的最小次数吗?
  • 为什么取MAX?因为是最坏的情况,所以取碎了与没碎中的最大情况。

代码如下:

int superEggDrop(int egg,int floor){
    int ans[floor+1][egg+1];
    for(int m = 1;m <= floor;m++)
        for(int n = 1;n <= egg;n++)
            ans[m][n] = m;//最坏的情况下,自然是所有楼层试一遍,同时这也是鸡蛋数为1时的答案

    for(int m = 1;m <= floor;m++)
        for(int n = 2;n <= egg;n++)//n必须从2开始,如果是1,就会出现ans[k-1][1-1=0],显然不存在0鸡蛋的情况
            for(int k = 1;k <= m-1;k++)
                ans[m][n] = min(ans[m][n],1+max(ans[k-1][n-1],ans[m-k][n]));
    return ans[floor][egg];
}

猜你喜欢

转载自www.cnblogs.com/MMMMMMMW/p/12406172.html