想象一下,你在一座有猫的高楼里。猫可以在低矮的故事窗外摔倒,但如果从高楼层抛出,它会死亡。你怎么能用最少的尝试来计算出猫可以存活的最长时间?
显然,如果你只有一只猫,那么你只能线性搜索。先从一楼扔猫。如果它存活下来,从第二个扔掉它。最终,从地板f抛出后,猫会死。然后你知道楼层f-1是最大的安全楼层。
但如果你有一只以上的猫怎么办?您现在可以尝试某种对数搜索。让我们说这个版本有100层,你有两个相同的猫。如果你将第一只猫从50楼扔出去并且死亡,那么你只需要线性搜索50个楼层。如果您为第一次尝试选择较低楼层,则可以做得更好。假设您选择一次解决20个楼层的问题,并且第一个致命楼层是#50。在这种情况下,你的第一只猫将在从60楼死亡之前从20楼和40楼的飞行中幸存下来。你只需要分别检查楼层41到49。这总共有12次尝试,这比你试图使用二进制消除所需的50次要好得多。
一般来说,对于有2只猫的n层建筑来说,什么是最好的策略和最坏情况的复杂性? n楼和m猫怎么样?
假设所有猫都是等同的:它们都将从给定窗口的摔倒中幸存或死亡。此外,每一次尝试都是独立的:如果一只猫在跌倒时幸存下来,它就完全没有受到伤害。
这不是家庭作业,虽然我可能已经解决了一次学校作业。这只是一个异想天开的问题,今天突然出现在我脑海中,我不记得解决方案了。如果有人知道此问题的名称或解决方案算法,则可获得奖励。
答案 0 :(得分:92)
根据a recent episode of Radiolab (about "Falling"),猫在9楼到达终点速度。之后,它会放松,不太可能受到伤害。从30日以上摔倒后,完全没有受伤的猫。最危险的楼层是5到9号。
答案 1 :(得分:70)
您可以轻松地为n层和m猫的一般情况编写一个小DP(动态编程)。
主要公式a[n][m] = min(max(a[k - 1][m - 1], a[n - k][m]) + 1) : for each k in 1..n
应该是不言自明的:
k - 1
个楼层要检查(k
}以及m - 1
只猫(a[k - 1][m - 1]
) 。 n - k
个楼层(k
以上的所有楼层)和m
只猫。 max
。+ 1
来自于我们刚刚使用过一次尝试(无论猫是否存活)。min(f(k)) : for k in 1..n
。它与 Gaurav Saxena 关于(100,2)的链接的Google结果一致。
int n = 100; // number of floors
int m = 20; // number of cats
int INFINITY = 1000000;
int[][] a = new int[n + 1][m + 1];
for (int i = 1; i <= n; ++i) {
// no cats - no game
a[i][0] = INFINITY;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
// i floors, j cats
a[i][j] = INFINITY;
for (int k = 1; k <= i; ++k) {
// try throw first cat from k-th floor
int result = Math.max(a[k - 1][j - 1], a[i - k][j]) + 1;
a[i][j] = Math.min(a[i][j], result);
}
}
}
System.out.println(a[n][m]);
如果您将最佳k
保存在另一个数组中,您可以轻松找到策略(如何抛出第一只猫)。
还有一个更快的解决方案,不涉及O(n ^ 3)计算,但我已经有点困了。
答案 2 :(得分:10)
想象一下,你在一座有猫的高楼里。猫可以在低矮的故事窗外摔倒,但如果从高楼层抛出,它会死亡。你怎么能用最少的尝试来计算出猫可以存活的最长时间?
解决这个问题的最佳策略是使用物理定律研究你的假设在一开始就是真实的概率。
如果你愿意的话,你会发现猫的生存机会实际上增加了距离地面的距离越高。当然,假设你从更高的建筑物(如石油塔)扔掉它,而不是更高的山峰,例如珠穆朗玛峰。
修改强>
实际上,你会看到一个未完成的骆驼分布
首先,猫死亡的概率很低(非常低的高度),然后它变得更高(低空),然后再降低(更高的高度),然后再高(高海拔)。
猫死亡作为地面高度函数的概率图如下所示:
(完成3,因为未完成的骆驼分发)
更新:
猫的终点速度为100公里/小时(60英里/小时)[= 27.7米/秒= 25.4码/秒]。
人体终点速度为210 km / h(130mph)。[= 75m / s = 68.58码/ s]
终端速度源:
http://en.wikipedia.org/wiki/Cat_righting_reflex
积分:
Goooooogle
我需要稍后核实:
http://en.wikipedia.org/wiki/Terminal_velocity
http://www.grc.nasa.gov/WWW/K-12/airplane/termv.html
答案 3 :(得分:8)
我首先在Steven Skiena的算法设计手册(练习8.15)中阅读了这个问题。它遵循动态编程的一章,但您不需要了解动态编程来证明策略的精确界限。首先是问题陈述,然后是下面的解决方案。
从足够高的高度落下时,鸡蛋会断裂。给定一层n层的建筑物,必须有一层楼层,以便鸡蛋从地板上掉落,但是从地板f-1掉落的鸡蛋能够存活下来。 (如果鸡蛋从任何地板上断裂,我们会说f = 1.如果鸡蛋从任何楼层中存活,我们会说f = n + 1)。
你寻求找到关键的楼层f。您可以执行的唯一操作是将鸡蛋放在某个楼层,看看会发生什么。你从k蛋开始,并尽可能少地下蛋。破碎的鸡蛋不能重复使用(完整的鸡蛋可以)。设E(k,n)是总是足够的蛋粪的最小数量。
- 显示E(1,n)= n。
- 显示
E(k,n) = Θ(n**(1/k))
。- 找到E(k,n)的重复。动态程序找到E(k,n)的运行时间是多少?
醇>
从第一层开始将鸡蛋从第一层开始丢弃,将在(最差)n次操作中找到关键层。
没有更快的算法。在任何算法的任何时候,让g看到蛋的最高层不会破裂。算法必须在任何更高的楼层h>之前测试楼层g + 1。 g + 1,否则如果蛋从地板h断裂,则无法区分f = g + 1和f = h。
首先,让我们考虑k = 2个蛋的情况,当n = r ** 2是一个完美的正方形。这是一个需要O(sqrt(n))时间的策略。首先以r层的增量丢弃第一个鸡蛋。当第一个鸡蛋断裂时,比如在ar
楼层,我们知道临界楼层f必须是(a-1)r < f <= ar
。然后我们从(a-1)r
开始从每个楼层放下第二个蛋。当第二个蛋破裂时,我们找到了关键的地板。我们在最多r时间丢弃每个蛋,因此该算法采用最差的2r操作,即Θ(sqrt(n))。
当n不是一个完美的正方形时,取r = ceil(sqrt(n)) ∈ Θ(sqrt(n))
。该算法保持Θ(sqrt(n))。
证明任何算法至少需要sqrt(n)时间。假设有一个更快的算法。考虑下降第一个蛋的地板顺序(只要它不会破裂)。由于它的下降小于sqrt(n),因此必须存在至少n / sqrt(n)的间隔,即sqrt(n)。当f在这个区间内时,算法将不得不用第二个蛋进行调查,并且必须逐层回忆1蛋的情况。矛盾。
为2个鸡蛋提供的算法可以很容易地扩展到k个鸡蛋。以恒定的间隔丢弃每个鸡蛋,这应该作为n的第k个根的力量。例如,对于n = 1000和k = 3,搜索间隔为100层,第一个蛋,10个第二个蛋,1个最后一个蛋。
同样,我们可以通过从k = 2证明中引入来证明没有算法更快Θ(n**(1/k))
。
我们通过优化丢弃第一个鸡蛋(地板g)的位置来推断复发,假设我们知道较小参数的最佳解决方案。如果鸡蛋破裂,我们在下面的g-1楼层用k-1鸡蛋进行探索。如果鸡蛋存活下来,我们在上面有n-g楼层用k蛋进行探索。魔鬼为我们选择了最坏的。因此,对于k> 1,复发
E(k,n) = min(max(E(k,n-g), E(k-1,g))) minimised over g in 1..n
答案 4 :(得分:2)
这不是假设您使用的是“同一只猫”吗?
你可以在数学上接近它,但这是关于数学的好处...有了正确的假设,0可以等于1(对于大的0值)。
从实际的角度来看,你可以得到'类似的猫',但你不能得到“同一只猫”。
你可以尝试根据经验确定答案,但我认为会有足够的统计差异,答案在统计上毫无意义。
您可以尝试使用“同一只猫”,但这不会起作用,因为在第一次掉落后,它不再是同一只猫。 (与此类似,一个人永远不会两次进入同一条河)
或者,你可以聚合猫的健康状况,以非常接近的间隔采样,并找到猫“大部分活着”的高度(与“公主新娘”中的“大部分死亡”相对)。猫将平均存活(直到最后一个间隔)。
我认为我偏离了原来的意图,但是如果你走的是经验路线,我会投票选择尽可能高的开始并随着身高的下降继续下降,直到他们在统计上存活下来。然后对幸存的猫进行重新测试以确定。
答案 5 :(得分:0)
我采用了稍微不同的方法来制作解决方案。
我首先使用 x cat和 y 猜测,使用以下方法计算出可以覆盖的最大楼层。
从1楼开始,继续增加猜测次数,同时跟踪检查的楼层,猜测它们已被检查,每层楼剩余的猫数量。
重复此操作直到 y 次。
这个非常效率低下的代码可用于计算给定的答案,但对少量的猫/地板非常有用。
Python代码:
def next_step(x, guess):
next_x = []
for y in x:
if y[0] == guess:
if y[1] != 1:
next_x.append((guess+1, y[1] - 1))
next_x.append(y)
if y[0] == guess:
next_x.append((guess+1, y[1]))
return next_x
x = [(1, TOTAL_NUM_CATS)]
current_floor = 1
while len(x) <= TOTAL_NUM_FLOORS:
x = next_step(x, current_floor)
current_floor += 1
print len(x)
对于2只猫,可以在x猜测中识别的最大楼层是:
1,3,6,10,15,21,28 ......
对于3只猫:
1,3,7,14,25,41,63 ......
4只猫:
1,3,7,15,30,56,98 ......
经过广泛研究(主要涉及将数字序列输入OEIS)后,我注意到 x 的最大楼层遵循combination分段模式。
2只猫:
n&lt; 2:2 ^ n - 1
n> = 2:C(n,1)+ C(n,2)
对于3只猫:
n&lt; 3:2 ^ n - 1
n> = 3:C(n,1)+ C(n,2)+ C(n,3)
4只猫:
n&lt; 4:2 ^ n - 1
n> = 4:C(n,1)+ C(n,2)+ C(n,3)+ C(n,4)
从这里开始,我采用简单的递增方法,直到我通过所需的楼层数。
Python代码:
def find_smallest(floors, eggs):
maximum_floors = 0
n = 0
while maximum_floors < floors:
maximum_floors = 0
n += 1
if n < eggs:
maximum_floors = 2**n - 1
else:
count = 0
for x in xrange(1, eggs+1):
maximum_floors += combination(n, x)
print n
这为(100,2)= 14提供了正确的解决方案 对于任何希望检查不那么微不足道的人,它会给出(1 000 000,5)= 43。
这在O(n)中运行,其中n是问题的答案(猫越多越好) 但是我确信一个具有更高数学水平的人可以简化在O(1)中计算的分段公式。
答案 6 :(得分:0)
O(m*(n^(1/m))) algorithm.
Let 'x' be the maximum number of attempts needed.
m = 1 => linear => x=n
m = 2:
Let the floors be split into 'k' partitions. The first cat is thrown at the end of each partition (max 'k' times).
When it dies, the second cat is used to go up from the beginning of this partition.
x = k + n/k.
Minimize x by diff wrt k and setting = 0, to get k = n^(1/2) and x = 2 * n^(1/2).
m = 3:
x = k + 2*(y^(1/2)), where y = n/k
diff wrt x and set = 0, to get k = n^(1/3) and x = 3 * n^(1/3)
for general m:
x = m * n^(1/m).
答案 7 :(得分:-1)
我无法阅读google blogspot(感谢博客作品),但我不认为直接的二进制风格搜索会是最好的。原因是二元搜索基于这样一种观念,即您正在寻找的答案在列表中的任何索引索引处具有相同的机会。但是在这种情况下,情况并非如此。在这种情况下,答案将更接近范围的一端而不是另一端。我不知道如何将其纳入搜索,但这是一个有趣的想法。
答案 8 :(得分:-1)