把猫扔出窗户


150

想象一下,您在猫的高楼大厦中。猫可以从低矮的窗户掉下来,但如果从高处摔落会死。您如何用最少的尝试次数找出猫可以存活的最长下落?

显然,如果您只有一只猫,则只能进行线性搜索。首先从一楼扔猫。如果它仍然存在,请从第二个开始扔掉。最终,从地板f掉下来的猫会死。然后,您知道f-1楼是最大安全楼。

但是,如果您有不止一只猫怎么办?现在,您可以尝试某种对数搜索。假设该建筑物有100层,而您有两只相同的猫。如果您将第一只猫扔出50层而死,那么您只需线性搜索50层。如果您第一次尝试选择较低的楼层,您甚至可以做得更好。假设您选择一次解决20层楼的问题,而第一个致命楼层是#50。在这种情况下,您的第一只猫将在20和40楼的飞行中幸存下来,然后从60楼死亡。您只需要分别检查41到49楼。总共进行了12次尝试,这比尝试使用二进制消除法所需的50次尝试要好得多。

通常,对于带有2只猫的n层建筑物,什么是最佳策略,哪一种是最坏情况的复杂性?n层和m只猫怎么办?

假设所有猫都是同等的:它们都将存活或死于从给定窗户掉落的猫。同样,每一次尝试都是独立的:如果一只猫摔倒幸存下来,那就完全没有伤害了。

这不是家庭作业,尽管我可能已经解决了一次学校作业。今天,这只是一个异想天开的问题,我不记得了。如果有人知道此问题或解决方案算法的名称,则奖励积分。


123
我反对以上述方式使用猫。我们可以把它换成狗吗?
Thilo

53
这不是那么简单。研究已经完成(猫不小心从摩天大楼上掉下来,没有被扔掉)。他们死亡的范围有一定范围,比他们生存的范围还高。关于他们如何张紧身体的一些事情。
安德鲁·谢泼德

5
我读过15英尺或以上的地方,猫有更大的生存机会。如果我们放弃前女友和/或na妻子,则此问题将更适合。
Anthony Forloney

34
您知道,如果您是从两只猫开始的,那么您可以等上几个月,然后运行二进制搜索。或者在此之后等待几个月,然后执行“同时搜索”,在此过程中,您会得到帮助人员同时从每层楼扔猫–在这种情况下,幸存猫的数量是您可以从中扔掉它们的最高层数。
mjfgates 2010年

10
对于兔子,将“月”更改为“周”。
mjfgates 2010年

Answers:


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楼扔下并死亡,我们现在可以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)计算,但是我已经有点困了。

编辑
哦,是的,我记得以前在哪里遇到过这个问题


嗯,不需要+ 1min()吗?就像您自己说的那样,无论尝试成功与否,这仍然是一次尝试。
j_random_hacker 2010年

@j_random_hacker它会改变什么吗?移动+1之外min。或将其移入max:)
Nikita Rybak 2010年

@Nikita:对不起,我以某种方式误读了您写的内容-根据我的说法,您所拥有的完全正确!+1。
j_random_hacker 2010年

请注意,这与Google Code Jam的“鸡蛋掉落问题”相同。的为O(n ^ 3)下面的解决方案是不够好,这是因为大的问题集使用N = 2000000000 code.google.com/codejam/contest/dashboard?c=32003#s=p2
ripper234

1
有关O(n)算法的信息,请参见此新问题。Google Code Jam的最高答案是O(n),但我还不了解。stackoverflow.com/questions/4699067/...
ripper234

92

根据Radiolab的最新一集(关于“跌倒”),猫在9楼达到了最终速度。之后,它会放松并且不太可能受到伤害。从30号上方跌落后,有完全未受伤的猫。最危险的楼层是第5到第9。


16
作为猫的人,我想指出的是,这项研究是基于动物防御事件发生后动物医院的报告。在此询问中,没有其他猫受伤或造成不便。
Thilo

16
不是答案,只是业务领域中的一些其他上下文。
Thilo

19
这个问题应有尽有。
Mark Ransom

2
这只是表明结果不是live = 1,die = 0,而是live = 1.0,die = 0.0,介于两者之间的都是概率。它也是需要发现的曲线而不是直线。
tadman 2010年

73
该报告的问题在于选择偏见-没有人将死猫送上兽医。
Niki Yoshiuchi 2010年

10

想象一下,您在猫的高楼大厦中。猫可以从低矮的窗户掉下来,但如果从高处摔落会死。您如何用最少的尝试次数找出猫可以存活的最长下落?

解决此问题的最佳策略是首先利用物理定律研究假设成立的可能性。

如果这样做的话,您会意识到,离地面的距离越大,猫的生存机会实际上就会增加。当然,假设您将它从更高的建筑物(如石油塔)扔掉,而不是从更高的山峰(如珠穆朗玛峰)扔掉。

编辑:
实际上,您会看到未完成的骆驼分配。
首先,猫死的概率很低(非常低的高度),然后变得更高(很低的高度),然后又变得更低(更高的高度),然后又更高(非常高的高度)。

猫死亡概率与地面海拔高度的关系图如下:(
以3结束,因为未分配的骆驼分布)

替代文字

更新:
猫的终极速度为100 km / h(60英里/小时)[= 27.7m / s = 25.4码/ s]。
人的终极速度为210 km / h(130mph)。[= 75m / s = 68.58 yards / s]

终端速度源:
http : //en.wikipedia.org/wiki/Cat_righting_reflex

积分:
糟糕,

我稍后需要验证:
http : //en.wikipedia.org/wiki/Terminal_velocity
http://www.grc.nasa.gov /WWW/K-12/airplane/termv.html



2
这样对吗?当然,一旦达到终极速度,机会就不会改变-我的印象是猫可以承受终极速度下降。
ZoFreX

4
@ZoFreX:当然可以,致命的是低于最终速度。另一方面,将一只猫从例如十万英里的高处掉下来,从真空中死后,它比掉下来活着的可能性更大。
David Thornley 2010年

1
那张图中的那些兔子耳朵吗?
ninjalj

1
@ZoFreX:角动量。由于猫的身体设计和猫的转弯技巧,由于角动量,猫总是会落在脚上。但这仍然意味着需要时间来解决。时间越长(==>海拔越高),猫落在脚上的可能性就越大(=例如,头顶着地的机会大大增加)。但是,您是对的,达到最终速度后,概率保持不变。我想说,猫很可能可以承受最终速度下降的影响,至少我的猫跳出浴室的窗户(约20m)而不会刮花。
Stefan Steiger,2010年

8

我首先在Steven Skiena的算法设计手册(练习8.15)中阅读了此问题。它紧随有关动态编程的一章,但您无需了解动态编程即可证明该策略的精确界限。首先是问题陈述,然后是下面的解决方案。

鸡蛋从足够高的高度掉落时会破裂。给定一幢n层建筑物,必须有一个f层,这样从f层掉落的鸡蛋可以破掉,但从f-1层掉落的鸡蛋可以幸免。(如果鸡蛋从任何一层破掉,我们将说f =1。如果鸡蛋从任何一层破掉,我们将说f = n + 1)。

您试图找到关键楼层f。您可以执行的唯一操作是将鸡蛋从地板上掉下来,看看会发生什么。您先从k个鸡蛋开始,然后尝试尽可能少地丢鸡蛋。破损的鸡蛋不能重复使用(完整的鸡蛋可以)。令E(k,n)为总能满足的最小排卵次数。

  1. 证明E(1,n)= n。
  2. 证明这一点E(k,n) = Θ(n**(1/k))
  3. 找出E(k,n)的递归。动态程序查找E(k,n)的运行时间是多少?

只有一个鸡蛋

从第一个楼层开始从每个楼层放下鸡蛋,这将在(最差)n次操作中找到关键楼层。

没有更快的算法。在任何算法中的任何时候,都应让g从不破坏鸡蛋的最高层开始。该算法必须在任何更高的楼层h> g + 1之前测试楼层g + 1,否则,如果鸡蛋要从楼层h断裂,则无法区分f = g + 1和f = h。

2个蛋

首先,让我们考虑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层。

类似地,我们可以Θ(n**(1/k))通过从k = 2证明来证明没有算法是更快的。

确切的解决方案

假设我们知道较小参数的最佳解决方案,则可以通过优化在第一个鸡蛋(第g层)的下垂位置推断出重复发生的可能性。如果鸡蛋破裂,我们将在下面的g-1层中探索k-1个鸡蛋。如果鸡蛋存活下来,我们可以在上面的ng层上用k个鸡蛋探索。魔鬼为我们选择了最坏的选择。因此,对于k> 1,递归

E(k,n) = min(max(E(k,n-g), E(k-1,g))) minimised over g in 1..n

如果我有k个鸡蛋,为什么O(k*n**(1/k))在最坏的情况下不能运行?因为在最坏的情况下,我必须经历n**(1/k) 确切的k时间。
Rakete1111 '18

2

这不是假设您使用的是“同一只猫”吗?

您可以用数学方法来处理它,但这对数学来说是件好事...在正确的假设下,0可以等于1(对于大值0)。

从实际的角度来看,您可以获得“类似的猫”,但不能获得“相同的猫”。

您可以尝试凭经验确定答案,但我认为统计差异将足以使答案在统计上毫无意义。

您可以尝试使用“同一只猫”,但这将不起作用,因为在第一次删除后,它不再是同一只猫。(与此类似,一个人永远不可能两次进入同一条河)

或者,您可以汇总猫的健康状况,以非常接近的时间间隔进行采样,然后找到猫“最活跃”的高度(与“公主新娘”中的“绝大部分”相对)。猫平均可以存活(直到最后一次间隔)。

我想我偏离了最初的意图,但是如果您沿着经验路线前进,我投票赞成从尽可能高的地方开始,并随着高度的降低而继续掉落猫,直到它们在统计上得以存活为止。然后再对存活的猫进行重新测试以确保。


0

我采用了略有不同的方法来产生解决方案。

我首先通过使用以下方法计算x猫和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,14,25,41,63 ...

4只猫:
1,3,7,15,15,30,56,98 ...

经过广泛的研究(主要涉及在OEIS中键入数字序列),我注意到x的最大下限遵循分段组合模式。

对于2只猫:
n <2:2 ^ n-1
n> = 2:C(n,1)+ C(n,2)

对于3只猫:
n <3:2 ^ n-1
n> = 3:C(n,1)+ C(n,2)+ C(n,3)

对于4只猫:
n <4:2 ^ n-1
n> = 4:C(n,1)+ C(n,2)+ C(n,3)+ C(n,4)

从这里开始,我采用简单的方法简单地递增n,直到我通过了所需的楼层数。

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)中进行计算。


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). 

-1

我无法在此阅读google blogspot(由于使用了blogwall),但我认为直接的二进制样式搜索不是最佳选择。原因是二进制搜索基于这样的概念,即您正在寻找的答案在列表中的任何索引索引处的机会均等。但是在这种情况下,那是不正确的。在这种情况下,答案将更有可能更接近范围的一端。我不知道如何将其纳入搜索范围,但这是一个有趣的想法。


1
我认为问题是最好的最坏情况,因此只要每个楼层都可以分配就无关紧要。
史蒂夫·杰索普

-1

所有这些关于猫的疯狂讨论..这只是一个猜测,猜出最少的问题(猫的数量)。也不必人工(且错误地)将无穷大定义为解决方案的一部分。该变量应被命名为上限或最大尝试或类似名称。问题定义(猫的东西)有一些严重的问题,人们对动物残酷的潜能做出了回应,而且现实生活中存在许多此类问题,例如空气拖曳,重力是加速度以及其他此类现实生活参数问题。因此,也许应该以完全不同的方式询问它。


FWIW这可能是一个隐蔽的现实生活问题。假设您有一个自动测试,该测试在1234版本上失败,但在42版上工作。该猫在1234上死了,但在42版上活了。什么版本的软件杀死了它?如果将例如从42升级到43既快速又容易,但是很难签出并重建新版本,则这看起来很像猫的问题。
mcdowella
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.