web-dev-qa-db-fra.com

Jeter les chats par les fenêtres

Imaginez que vous êtes dans un grand immeuble avec un chat. Le chat peut survivre à une chute d'une fenêtre basse, mais il mourra s'il est projeté d'un étage élevé. Comment pouvez-vous déterminer la plus longue chute que le chat peut survivre, en utilisant le moins de tentatives?

De toute évidence, si vous n'avez qu'un seul chat, vous ne pouvez effectuer une recherche linéaire. Jetez d'abord le chat du premier étage. S'il survit, lancez-le à partir du second. Finalement, après avoir été jeté du sol f, le chat mourra. Vous savez alors que le plancher f-1 était le plancher sécuritaire maximal.

Mais que faire si vous avez plus d'un chat? Vous pouvez maintenant essayer une sorte de recherche logarithmique. Disons que la construction a 100 étages et que vous avez deux chats identiques. Si vous jetez le premier chat hors du 50e étage et qu'il meurt, alors vous n'avez qu'à chercher 50 étages linéairement. Vous pouvez faire encore mieux si vous choisissez un étage inférieur pour votre première tentative. Disons que vous choisissez de vous attaquer au problème 20 étages à la fois et que le premier étage fatal est le n ° 50. Dans ce cas, votre premier chat survivra aux vols des étages 20 et 40 avant de mourir du sol 60. Il vous suffit de vérifier les étages 41 à 49 individuellement. C'est un total de 12 tentatives, ce qui est bien mieux que les 50 dont vous auriez besoin si vous aviez tenté d'utiliser l'élimination binaire.

En général, quelle est la meilleure stratégie et la complexité la plus défavorable pour un bâtiment à n étages avec 2 chats? Et pour n étages et m chats?

Supposons que tous les chats sont équivalents: ils survivront tous ou mourront d'une chute d'une fenêtre donnée. De plus, chaque tentative est indépendante: si un chat survit à une chute, il est complètement indemne.

Ce ne sont pas des devoirs, même si je l'ai peut-être résolu une fois pour les devoirs. C'est juste un problème fantaisiste qui m'est venu à l'esprit aujourd'hui et je ne me souviens pas de la solution. Points bonus si quelqu'un connaît le nom de ce problème ou de l'algorithme de solution.

150
AndrewF

Selon n épisode récent de Radiolab (sur "Falling") , un chat atteint sa vitesse terminale au 9ème étage. Après cela, il se détend et est moins susceptible d'être blessé. Il y a des chats complètement indemnes après une chute au-dessus du 30. Les étages les plus risqués sont du 5e au 9e.

92
Thilo

Imaginez que vous êtes dans un grand immeuble avec un chat. Le chat peut survivre à une chute d'une fenêtre basse, mais il mourra s'il est projeté d'un étage élevé. Comment pouvez-vous déterminer la plus longue chute que le chat peut survivre, en utilisant le moins de tentatives?

La meilleure stratégie pour résoudre ce problème consiste à étudier, en utilisant la loi de la physique, la probabilité que vos hypothèses soient vraies en premier lieu.

Si vous l'aviez fait, vous vous rendriez compte que les chances de survie du chat augmentent réellement plus la distance au sol est élevée. Bien sûr, en supposant que vous le jetiez d'un bâtiment toujours plus haut, comme les tours Petronas, et non d'une montagne toujours plus haute, comme le mont Everest.

Modifier:
En fait, vous verriez une distribution de chameaux inachevée.
.

Le graphique de la probabilité de mort du chat en fonction de l'altitude au-dessus du sol ressemble à ceci:
(terminer à 3, car la distribution de chameaux est inachevée)

alt text

Mise à jour:
La vitesse terminale d'un chat est de 100 km/h (60 mph) [= 27,7 m/s = 25,4 yards/s].
La vitesse terminale humaine est de 210 km/h (130 mph). [= 75 m/s = 68,58 yards/s]

Source de vitesse terminale:
http://en.wikipedia.org/wiki/Cat_righting_reflex

Crédits:
Goooooogle

Je dois vérifier plus tard:
http://en.wikipedia.org/wiki/Terminal_velocity
http://www.grc.nasa.gov/WWW/K-12/airplane/termv.html


10
Stefan Steiger

J'ai d'abord lu ce problème dans le manuel de conception d'algorithmes de Steven Skiena (exercice 8.15). Il a suivi un chapitre sur la programmation dynamique, mais vous n'avez pas besoin de connaître la programmation dynamique pour prouver des limites précises sur la stratégie. D'abord l'énoncé du problème, puis la solution ci-dessous.

Les œufs se cassent lorsqu'ils tombent d'une hauteur suffisamment grande. Étant donné un bâtiment de n étages, il doit y avoir un étage f tel que les œufs tombés du plancher f se cassent, mais les œufs tombés du plancher f-1 survivent. (Si l'œuf se casse d'un étage, nous dirons f = 1. Si l'œuf survit à n'importe quel étage, nous dirons f = n + 1).

Vous cherchez à trouver le plancher critique f. La seule opération que vous pouvez effectuer est de déposer un œuf sur un sol et de voir ce qui se passe. Vous commencez avec k oeufs et cherchez à en faire tomber le moins de fois possible. Les œufs cassés ne peuvent pas être réutilisés (les œufs intacts le peuvent). Soit E (k, n) le nombre minimum d'excréments d'oeufs qui suffira toujours.

  1. Montrez que E (1, n) = n.
  2. Montrez que E(k,n) = Θ(n**(1/k)).
  3. Trouvez une récurrence pour E (k, n). Quel est le temps d'exécution du programme dynamique pour trouver E (k, n)?

Un seul œuf

Laisser tomber l'oeuf de chaque étage en commençant par le premier trouvera l'étage critique dans (au pire) n opérations.

Il n'y a pas d'algorithme plus rapide. À tout moment dans n'importe quel algorithme, laissez g le dernier étage d'où l'œuf a été vu ne pas se casser. L'algorithme doit tester l'étage g + 1 avant tout étage supérieur h> g + 1, sinon si l'œuf venait à se détacher de l'étage h, il ne pourrait pas faire la distinction entre f = g + 1 et f = h.

2 oeufs

Tout d'abord, considérons le cas des œufs k = 2, lorsque n = r ** 2 est un carré parfait. Voici une stratégie qui prend O(sqrt(n)) fois. Commencez par déposer le premier œuf par incréments de r étages. Lorsque le premier œuf se casse, par exemple à l'étage ar , nous savons que le plancher critique f doit être (a-1)r < f <= ar. Nous déposons ensuite le deuxième œuf de chaque étage à partir de (a-1)r. Lorsque le deuxième œuf se casse, nous avons trouvé le plancher critique. Nous avons déposé chacun Egg au plus r fois, donc cet algorithme prend au pire 2r opérations, qui est Θ (sqrt (n)).

Lorsque n n'est pas un carré parfait, prenez r = ceil(sqrt(n)) ∈ Θ(sqrt(n)). L'algorithme reste Θ (sqrt (n)).

Preuve que tout algorithme prend au moins sqrt (n) temps. Supposons qu'il existe un algorithme plus rapide. Considérez la séquence de planchers d'où il laisse tomber le premier œuf (tant qu'il ne se casse pas). Puisqu'il baisse moins de sqrt (n), il doit y avoir un intervalle d'au moins n/sqrt (n) qui est sqrt (n). Lorsque f est dans cet intervalle, l'algorithme devra l'étudier avec le deuxième œuf, et cela doit être fait étage par étage en rappelant le cas de 1 œuf. CONTRADICTION.

k oeufs

L'algorithme présenté pour 2 œufs peut être facilement étendu à k œufs. Déposez chaque œuf avec des intervalles constants, qui doivent être pris comme les puissances de la racine kième de n. Par exemple, pour n = 1000 et k = 3, recherchez des intervalles de 100 étages avec le premier œuf, 10 avec le deuxième œuf et 1 avec le dernier œuf.

De même, nous pouvons prouver qu'aucun algorithme n'est plus rapide Θ(n**(1/k)) en induisant à partir de la preuve k = 2.

Solution exacte

Nous déduisons la récurrence en optimisant où déposer le premier œuf (plancher g), en supposant que nous connaissons des solutions optimales pour des paramètres plus petits. Si l'oeuf se casse, nous avons les étages g-1 ci-dessous pour explorer avec des oeufs k-1. Si l'œuf survit, nous avons des étages n-g au-dessus pour explorer avec k œufs. Le diable choisit le pire pour nous. Ainsi pour k> 1 la récurrence

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

Cela ne suppose-t-il pas que vous utilisez "The Same Cat"?

Vous pouvez l'approcher mathématiquement, mais c'est la bonne chose à propos des mathématiques ... avec les bonnes hypothèses, 0 peut être égal à 1 (pour les grandes valeurs de 0).

D'un point de vue pratique, vous pouvez obtenir des "chats similaires", mais pas "le même chat".

Vous pourriez essayer de déterminer la réponse de manière empirique, mais je pense qu'il y aurait suffisamment de différences statistiques pour que la réponse soit statistiquement dénuée de sens.

Vous pouvez essayer d'utiliser "The Same Cat", mais cela ne fonctionnera pas, car, après la première goutte, ce n'est plus le même chat. (De la même façon, onecan ne peut jamais entrer deux fois dans la même rivière)

Ou, vous pouvez agréger la santé du chat, en échantillonnant à des intervalles extrêmement rapprochés, et trouver les hauteurs pour lesquelles le chat est "principalement vivant" (par opposition à "principalement mort" de "The Princess Bride"). Les chats survivront en moyenne (jusqu'au dernier intervalle).

Je pense que je me suis éloigné de l'intention initiale, mais si vous suivez la voie empirique, je vote pour commencer le plus haut possible et continuer à laisser tomber les chats à mesure que la taille diminue jusqu'à ce qu'ils survivent statistiquement. Et refaites un test sur les chats survivants pour en être sûr.

2
Marc

J'ai pris une méthode légèrement différente pour produire une solution.

J'ai commencé par déterminer le plancher maximum qui pourrait être couvert en utilisant x chats et y devine en utilisant la méthode suivante.

Commencez avec 1 étage et continuez à augmenter le nombre de suppositions tout en gardant une trace des étages vérifiés, qui supposent qu'ils ont été vérifiés et combien de chats restaient pour chaque étage.
Répétez cette opération jusqu'à y fois.

Ce code très inefficace pour calculer la réponse donnée mais néanmoins utile pour un petit nombre de chats/étages.

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

Pour 2 chats, les étages maximum qui peuvent être identifiés en x suppositions sont:
1, 3, 6, 10, 15, 21, 28 ...

Pour 3 chats:
1, 3, 7, 14, 25, 41, 63 ...

Pour 4 chats:
1, 3, 7, 15, 30, 56, 98 ...

Après des recherches approfondies (impliquant principalement la saisie de séquences de nombres dans OEIS ), j'ai remarqué que le nombre maximal d'étages pour x suit un - combinaison motif par morceaux.

Pour 2 chats:
n <2: 2 ^ n - 1
n> = 2: C (n, 1) + C (n, 2)

Pour 3 chats:
n <3: 2 ^ n - 1
n> = 3: C (n, 1) + C (n, 2) + C (n, 3)

Pour 4 chats:
n <4: 2 ^ n - 1
n> = 4: C (n, 1) + C (n, 2) + C (n, 3) + C (n, 4)

À partir de là, j'ai adopté l'approche facile de l'incrémentation simple n jusqu'à ce que je passe le nombre d'étages requis.

Code 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

Cela donne la bonne solution pour (100, 2) = 14.
Pour quiconque souhaite vérifier quelque chose de moins trivial, cela donne (1 000 000, 5) = 43.

Cela s'exécute dans O(n) où n est la réponse au problème (plus il y a de chats, mieux c'est).
Cependant, je suis sûr qu'une personne possédant un niveau de mathématiques plus élevé pourrait simplifier les formules par morceaux pour calculer dans O (1).

0
threenplusone
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). 
0
tldr