玻璃球临界层问题

曾经在面试的时候碰到过一个问题,回想起来很有意思:

有一栋100层高的大楼,给你两个完全质地的玻璃球。从某一层开始,丢下玻璃球会摔碎。那么,用什么方法,能使用尽可能少的次数,知道这个临界的层是第几层?

方法一
我们知道,最差的方法就是从第1层开始,一层一层向上找,直到第100层玻璃球摔碎。这种方法最坏可能要找100次。

方法二
我第一瞬间想到的就是这种方法,采用类似于二分法的方法。我们将第一个球从中间位置(第50层)开始扔,假如摔碎,则临界层在第1-49层,那用第二个球一层一层找。假如没摔碎则在第51-100层继续使用二分法。这个方法在最坏情况下,需要尝试50次。

方法三
后来面试官引导,可以优化一下这个二分法吗?我就在想,是否可以分区,将100层楼,每10层楼分一个区,先将第一个球在第10层,第20层,第30层扔,假如在第30层摔碎,那么临界层一定在第21-30层之间。那么用第二个球一层一层试。最坏的情况是在第100层碎掉,尝试次数为 10 + 9 = 19次。

方法四
对分区方法的优化,可以想到一种类似于动态规划的方法,将大问题划分为小问题。我们从较低的楼层开始,每次增加一个固定的间隔。假设我们从第x层开始,然后从x + (x-1)层,x + (x-1) + (x-2)层,依此类推。在最坏的情况下,我们希望尝试次数最小化,因此我们选择x使得x + (x-1) + (x-2) + … + 1 >= 100。通过计算,我们可以得到x = 14。因此,我们首先从第14层开始尝试,然后从第27层(14 + 13)开始,以此类推。在最坏的情况下,这种方法需要尝试14次。

方法五
我们可以使用动态规划来找到在给定楼层数和玻璃球数的条件下,需要尝试的最小次数。我们定义dp(n, k)为在n层楼和k个球的情况下,需要尝试的最小次数。我们需要找到状态转移方程和边界条件。
边界条件:
如果只有一个球,那么我们需要从第1层开始逐层尝试,所以dp(n, 1) = n。
如果楼层只有1层或0层,那么我们只需要尝试一次或者不需要尝试,所以dp(1, k) = 1 和 dp(0, k) = 0。
状态转移方程:
对于dp(n, k),我们可以从第i层扔下一个球。有两种情况:
球碎了,那么我们需要在i-1层和k-1个球的情况下继续寻找,即dp(i-1, k-1)。
球没有碎,那么我们需要在剩下的n-i层和k个球的情况下继续寻找,即dp(n-i, k)。
所以状态转移方程为:
dp(n, k) = 1 + min(max(dp(i-1, k-1), dp(n-i, k))),其中i从1到n。加1表示我们需要将当前这一次的尝试次数计入总数中

下面是C++的实现方法:

int min_drops(int n, int k) {
    // 初始化dp数组
    vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));

    // 边界条件
    for (int i = 1; i <= n; ++i) {
        dp[i][1] = i;
    }
    for (int j = 1; j <= k; ++j) {
        dp[1][j] = 1;
        dp[0][j] = 0;
    }

    // 动态规划
    for (int i = 2; i <= n; ++i) {
        for (int j = 2; j <= k; ++j) {
            int min_val = INT_MAX;
            for (int x = 1; x <= i; ++x) {
                int temp = max(dp[x - 1][j - 1], dp[i - x][j]);
                min_val = min(min_val, temp);
            }
            dp[i][j] = 1 + min_val;
        }
    }

    return dp[n][k];
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值