鸡蛋掉落问题的变种——带成本限制的鸡蛋掉落
题目描述
你有 \(k\) 枚相同的鸡蛋,并可以进入一栋从 1 层到 \(n\) 层的建筑物。已知存在一个楼层 \(f\)(\(0 \leq f \leq n\)),从低于或等于 \(f\) 的楼层扔鸡蛋不会碎,而从高于 \(f\) 的楼层扔鸡蛋会碎。每次操作,你可以选择一座楼层 \(x\)(\(1 \leq x \leq n\))并扔下一枚鸡蛋:
- 如果鸡蛋没碎,你可以继续使用这枚鸡蛋,并考虑更高的楼层(即 \(x+1\) 到 \(n\) 层)。
- 如果鸡蛋碎了,这枚鸡蛋就不能再用了,且你需要考虑更低的楼层(即 1 到 \(x-1\) 层)。
此外,每次扔鸡蛋都有成本:在第 \(i\) 层扔鸡蛋的成本为 \(c[i]\)(\(c[i] > 0\))。你的目标是以最小的总成本,在最坏情况下确定 \(f\) 的具体值(即明确 \(f\) 是哪个楼层)。注意:如果鸡蛋在某一层碎了,后续的测试只能在更低的楼层进行;如果没碎,则可在更高楼层测试。你需要保证无论 \(f\) 的实际值是多少,你的测试方案都能确定它,并最小化最坏情况下的总成本。
解题思路
这是一个动态规划问题,结合了经典的“鸡蛋掉落”和最优化成本。我们需要一个策略,在最坏情况下(即对于所有可能的 \(f\)),都能确定临界楼层,并且使得总成本最小。
定义状态
设 \(dp[i][j]\) 表示:当你有 \(i\) 枚鸡蛋可用,并且需要测试的楼层范围为 \(1\) 到 \(j\) 层时,在最坏情况下确定临界楼层所需的最小总成本。
- 这里“测试的楼层范围”是指,我们已经知道临界楼层 \(f\) 在区间 \([1, j]\) 内(包括 0 层表示鸡蛋从 1 层就开始碎,但通常从 1 开始)。
- 目标:计算 \(dp[k][n]\)。
状态转移
假设我们当前有 \(i\) 枚鸡蛋,需要测试 \(j\) 层楼。我们选择在第 \(x\) 层(\(1 \leq x \leq j\))扔一个鸡蛋。此时发生两种情况:
-
鸡蛋碎了:说明临界楼层 \(f\) 小于 \(x\),即 \(f\) 在 \([1, x-1]\) 中。我们还剩 \(i-1\) 枚鸡蛋,需要测试 \(x-1\) 层楼。因此,此情况下的最坏成本是:
\(\text{cost}_{\text{broken}} = c[x] + dp[i-1][x-1]\)。 -
鸡蛋没碎:说明临界楼层 \(f\) 大于等于 \(x\),即 \(f\) 在 \([x, j]\) 中。但注意,由于没碎,我们仍然有 \(i\) 枚鸡蛋可用,但只需测试从 \(x\) 到 \(j\) 的楼层。不过,我们已知 \(f \geq x\),因此等价于测试 \(j-x\) 层楼(将楼层重新编号为 1 到 \(j-x\))。此情况下的最坏成本是:
\(\text{cost}_{\text{survive}} = c[x] + dp[i][j-x]\)。
对于这个选择 \(x\),最坏情况是两种情况下成本的最大值(因为我们不知道鸡蛋会不会碎,必须考虑最坏的情况):
\[\text{cost}(x) = c[x] + \max(dp[i-1][x-1],\; dp[i][j-x]) \]
我们要最小化这个最坏成本,所以状态转移方程为:
\[dp[i][j] = \min_{1 \leq x \leq j} \left\{ c[x] + \max(dp[i-1][x-1], dp[i][j-x]) \right\} \]
边界条件
- 如果 \(i = 0\):没有鸡蛋可用,无法测试,但按题意不可能(因为鸡蛋数至少为 1)。我们可以设 \(dp[0][j] = \infty\)(无效)。
- 如果 \(i = 1\):只有一枚鸡蛋,只能从低到高逐层尝试,直到鸡蛋碎掉或到达顶层。最坏情况下,我们需要尝试所有楼层,总成本是 \(\sum_{t=1}^j c[t]\)。
- 如果 \(j = 0\):没有楼层需要测试,成本为 0。即 \(dp[i][0] = 0\)。
初始化和计算顺序
我们需要计算 \(dp[i][j]\) 对于 \(i = 1\) 到 \(k\),\(j = 1\) 到 \(n\) 的值。
- 先初始化 \(i=1\) 的情况:\(dp[1][j] = \sum_{t=1}^j c[t]\)。
- 然后按 \(i\) 从小到大,\(j\) 从小到大计算。
时间复杂度
直接按上述转移计算,对每个 \((i, j)\) 需要枚举 \(x\) 从 1 到 \(j\),总复杂度为 \(O(k n^2)\)。当 \(n\) 较大时可能较慢,但题目通常 \(n\) 和 \(k\) 不会特别大(如几百)。可以进一步优化,但这里我们先理解基础DP。
举例说明
假设 \(n=3\) 层楼,\(k=2\) 个鸡蛋,成本数组 \(c = [1, 2, 3]\)(楼层 1、2、3 的成本分别为 1、2、3)。
我们计算 \(dp[2][3]\):
- 初始:\(dp[1][1] = 1\), \(dp[1][2] = 1+2=3\), \(dp[1][3] = 1+2+3=6\)。
- 对于 \(dp[2][1]\):只有 1 层楼,只需在 1 层试一次,成本 \(c[1] = 1\)。也可以从公式:枚举 \(x=1\):
\[ dp[2][1] = c[1] + \max(dp[1][0], dp[2][0]) = 1 + \max(0,0) = 1 \]
- 对于 \(dp[2][2]\):枚举 \(x=1,2\)。
- \(x=1\):成本 = \(c[1] + \max(dp[1][0], dp[2][1]) = 1 + \max(0,1) = 2\)。
- \(x=2\):成本 = \(c[2] + \max(dp[1][1], dp[2][0]) = 2 + \max(1,0) = 3\)。
取最小值 2,所以 \(dp[2][2] = 2\)。
- 对于 \(dp[2][3]\):枚举 \(x=1,2,3\)。
- \(x=1\):成本 = \(1 + \max(dp[1][0], dp[2][2]) = 1 + \max(0,2) = 3\)。
- \(x=2\):成本 = \(2 + \max(dp[1][1], dp[2][1]) = 2 + \max(1,1) = 4\)。
- \(x=3\):成本 = \(3 + \max(dp[1][2], dp[2][0]) = 3 + \max(3,0) = 6\)。
取最小值 3,所以 \(dp[2][3] = 3\)。
因此,最小最坏总成本为 3。
算法总结
- 初始化 \(dp[1][j] = \sum_{t=1}^j c[t]\),\(dp[i][0] = 0\)。
- 对于 \(i=2\) 到 \(k\):
- 对于 \(j=1\) 到 \(n\):
- 枚举 \(x\) 从 1 到 \(j\),计算:
- 对于 \(j=1\) 到 \(n\):
\[ \text{cost} = c[x] + \max(dp[i-1][x-1], dp[i][j-x]) \]
- 取最小值赋给 $ dp[i][j] $。
- 最终结果 = \(dp[k][n]\)。
进一步优化
对于固定的 \(i\),注意到 \(dp[i-1][x-1]\) 随 \(x\) 增加而增加,而 \(dp[i][j-x]\) 随 \(x\) 增加而减少。因此,最优的 \(x\) 通常是两者接近的位置,可以用二分查找来优化,将时间复杂度降到 \(O(k n \log n)\)。不过,基础DP已足够理解问题本质。