Jeter des chats par les fenêtres


150

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

De toute évidence, si vous n'avez qu'un seul chat, vous ne pouvez rechercher que linéairement. Jetez d'abord le chat du premier étage. S'il survit, lancez-le dès le second. Finalement, après avoir été jeté du sol f, le chat mourra. Vous savez alors que l'étage f-1 était l'étage maximal de sécurité.

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, vous n'avez qu'à fouiller 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 mortel est le # 50. Dans ce cas, votre premier chat survivra aux vols des étages 20 et 40 avant de mourir à partir du 60e étage. Il vous suffit de vérifier les étages 41 à 49 individuellement. Cela représente un total de 12 tentatives, ce qui est bien mieux que les 50 dont vous auriez besoin si vous tentiez d'utiliser l'élimination binaire.

En général, quelle est la meilleure stratégie et le pire des cas de complexité pour un bâtiment de 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 une affectation scolaire. C'est juste un problème fantaisiste qui m'est venu à l'esprit aujourd'hui et je ne me souviens pas de la solution. Des points bonus si quelqu'un connaît le nom de ce problème ou de l'algorithme de solution.


123
Je m'oppose à l'utilisation de chats de la manière décrite. Pouvons-nous le changer en chiens?
Thilo

53
Ce n'est pas aussi simple. Des études ont été menées (sur des chats tombant accidentellement des gratte-ciel sans être jetés). Il y avait une certaine fourchette où ils sont morts, et une fourchette *** plus élevée que celle où ils ont survécu. Quelque chose sur la façon dont ils ont tendu leur corps.
Andrew Shepherd

5
J'ai lu quelque part que 15 pieds ou plus, les chats ont une plus grande chance de survivre. Cette question serait mieux adaptée si nous abandonnions d'anciennes petites amies et / ou des épouses harcelantes.
Anthony Forloney

34
Vous savez, si vous commencez avec deux chats, vous POUVEZ attendre quelques mois, puis lancer une recherche binaire. Ou attendez quelques mois après cela et faites une «recherche simultanée», dans laquelle vous obtenez des aides pour jeter les chats de tous les étages simultanément - le nombre de chats survivants dans ce cas est le numéro d'étage le plus élevé à partir duquel vous pouvez les jeter, bien sûr .
mjfgates

10
Avec les lapins, remplacez "mois" par "semaines".
mjfgates

Réponses:


70

Vous pouvez facilement écrire un peu de DP (programmation dynamique) pour le cas général de n étages et m chats.

La formule principale,, a[n][m] = min(max(a[k - 1][m - 1], a[n - k][m]) + 1) : for each k in 1..ndevrait être explicite:

  • Si le premier chat est jeté du k-ème étage et meurt, nous avons maintenant des k - 1étages à vérifier (tous ci-dessous k) et des m - 1chats ( a[k - 1][m - 1]).
  • Si le chat survit, il n - kreste des étages (tous les étages supérieurs k) et encore des mchats.
  • Le pire des cas de deux devrait donc être choisi max.
  • + 1 vient du fait que nous venons d'utiliser une seule tentative (que le chat ait survécu ou non).
  • Nous essayons tous les étages possibles pour trouver le meilleur résultat min(f(k)) : for k in 1..n.

Il est en accord avec le résultat de Google du lien de Gaurav Saxena pour (100, 2).

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]);

Vous pouvez facilement trouver une stratégie (comment lancer le premier chat), si vous enregistrez le mieux kdans un autre tableau.

Il existe également une solution plus rapide, n'impliquant pas de calculs O (n ^ 3), mais j'ai déjà un peu sommeil.

edit
Oh ouais, je me souviens où j'ai vu ce problème avant .


Hmm, n'est-ce pas le + 1besoin d'être en dehors du min()? Comme vous le dites vous-même, que la tentative réussisse ou non, c'est toujours une tentative.
j_random_hacker

@j_random_hacker Cela change-t-il quelque chose? Se déplacer à l' +1extérieur de min. Ou le déplacer à l'intérieur de max:)
Nikita Rybak

@Nikita: Je suis désolé d'avoir mal lu ce que vous aviez écrit - ce que vous avez est tout à fait exact selon moi! +1.
j_random_hacker

Notez que cela est identique au "problème de goutte d'oeuf" de Google Code Jam. La solution O (n ^ 3) ci-dessous n'est pas suffisante, car le grand ensemble de problèmes utilise N = 2000000000. code.google.com/codejam/contest/dashboard?c=32003#s=p2
ripper234

1
Voir cette nouvelle question pour un algorithme O (n). La réponse principale au Google Code Jam est O (n), mais je ne la comprends pas encore. stackoverflow.com/questions/4699067/…
ripper234

92

Selon un é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 risque moins d'être blessé. Il y a des chats complètement indemnes après une chute de dessus le 30. Les étages les plus risqués sont du 5e au 9e.


16
En tant que chat, je tiens à souligner que cette étude était basée sur des rapports d'hôpitaux pour animaux après des incidents de défenestration. Aucun chat supplémentaire n'a été blessé ou incommodé dans cette enquête.
Thilo

16
Pas de réponse, juste un contexte supplémentaire du domaine commercial.
Thilo

19
C'est autant de réponse que la question le mérite.
Mark Ransom

2
Cela montre simplement comment ce n'est pas un cas de live = 1, die = 0 comme résultat, mais plus de live = 1.0, die = 0.0 et tout ce qui se trouve entre les deux est des probabilités. C'est aussi une courbe, pas une ligne, qui doit être découverte.
tadman

73
Le problème avec ce rapport est le biais de sélection - personne ne prend un chat mort chez le vétérinaire.
Niki Yoshiuchi

10

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

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 en fait 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.

Edit:
En fait, vous verriez une distribution de chameaux inachevée.
Premièrement, la probabilité que le chat meure est faible (très basse altitude), puis elle augmente (basse altitude), puis à nouveau plus basse (altitude plus élevée), puis à nouveau plus élevée (très haute altitude).

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

texte alternatif

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 du terminal:
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



2
Est-ce correct? Une fois que la vitesse terminale est atteinte, les chances ne peuvent pas changer - et j'avais l'impression qu'un chat peut survivre à une chute de vitesse terminale.
ZoFreX

4
@ZoFreX: Bien sûr qu'ils le peuvent, c'est la vitesse juste en dessous de la limite qui est la plus fatale. D'un autre côté, laissez tomber un chat, disons à cent mille kilomètres d'altitude, et le chat est plus susceptible de brûler dans l'atmosphère après être mort du vide que de tomber et de vivre.
David Thornley

1
Ces oreilles de lapin sont-elles dans ce graphique?
ninjalj

1
@ZoFreX: Moment angulaire. Un chat atterrit toujours sur ses pieds, en raison de l'élan angulaire en raison de la conception du corps du chat et des capacités de rotation du chat. Mais cela signifie toujours qu'il a besoin de temps pour tourner. Plus il y a de temps (==> plus l'altitude est élevée), plus le chat a de chances d'atterrir sur ses pattes (==> les chances de survie augmentent considérablement, par opposition à un atterrissage sur la tête par exemple). Mais vous avez raison, la probabilité reste la même après avoir atteint la vitesse terminale. Je dirais qu'il est fort probable qu'un chat puisse survivre à une chute de vitesse terminale, au moins le mien a sauté par la fenêtre de la salle de bain (environ 20 m), sans égratignure.
Stefan Steiger

8

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 sont tombés d'une hauteur suffisante. Étant donné un bâtiment de n étages, il doit y avoir un étage f tel que les œufs tombés de l'étage f se cassent, mais les œufs tombés de l'étage f-1 survivent. (Si l'œuf se brise de n'importe quel étage, nous dirons f = 1. Si l'œuf survit de 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 œufs et cherchez à déposer des œufs 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 de crottes d'œufs qui suffira toujours.

  1. Montrez que E (1, n) = n.
  2. Montrez ça E(k,n) = Θ(n**(1/k)).
  3. Trouvez une récurrence pour E (k, n). Quelle est la durée d'exécution du programme dynamique pour trouver E (k, n)?

Seulement 1 œuf

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

Il n'y a pas d'algorithme plus rapide. A 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 le plancher g + 1 avant tout étage supérieur h> g + 1, sinon si l'œuf venait à se casser du plancher 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 k = 2 œufs, lorsque n = r ** 2 est un carré parfait. Voici une stratégie qui prend O (sqrt (n)) temps. Commencez par déposer le premier œuf par incréments de r étages. Lorsque le premier œuf se brise, disons au sol ar, nous savons que le sol 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 brise, nous avons trouvé le plancher critique. Nous avons déposé chaque œuf au plus r fois, donc cet algorithme prend au pire 2r opérations, ce 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 d'étages à partir de laquelle il laisse tomber le premier œuf (tant qu'il ne se brise pas). Comme il tombe moins que 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 œufs

L'algorithme présenté pour 2 œufs peut être facilement étendu à k œufs. Déposez chaque œuf avec des intervalles constants, qui devraient être considérés comme les puissances de la kème racine 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 l'endroit où déposer le premier œuf (plancher g), en supposant que nous connaissons des solutions optimales pour des paramètres plus petits. Si l'œuf se brise, nous avons les étages g-1 ci-dessous à explorer avec des œufs k-1. Si l'œuf survit, nous avons ng étages au-dessus à 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

Si j'ai k œufs, pourquoi le runtime n'est-il pas O(k*n**(1/k))dans le pire des cas? Puisque dans le pire des cas, je dois traverser des moments n**(1/k) précis k.
Rakete1111

2

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

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

D'un point de vue pratique, vous pouvez obtenir «Similar Cats», mais vous ne pouvez pas obtenir «The Same Cat».

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 pourriez essayer d'utiliser "The Same Cat", mais cela ne fonctionnerait pas, car après la première goutte, ce n'est plus le même chat. (De la même manière, on ne peut jamais entrer deux fois dans la même rivière)

Ou, vous pouvez agréger la santé du chat, échantillonner à des intervalles extrêmement rapprochés, et trouver les hauteurs pour lesquelles le chat est «surtout vivant» (par opposition à «presque 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 aussi haut que possible et continuer à laisser tomber les chats à mesure que la taille diminue jusqu'à ce qu'ils survivent statistiquement. Et puis refaites le test sur les chats survivants pour être sûr.


0

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

J'ai commencé par déterminer le plancher maximal qui pourrait être couvert en utilisant x chats et y suppositions 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, de la supposition sur laquelle ils ont été vérifiés et du nombre de chats restants 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, le nombre maximum d'étages pouvant être identifiés en x estimations est:
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 les étages maximums pour x suivent un modèle de combinaison 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 simple consistant à incrémenter simplement 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 fonctionne en 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 avec un niveau plus élevé de mathématiques pourrait simplifier les formules par morceaux à calculer en 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

Je ne peux pas lire le blogspot google à ce sujet (grâce aux travaux blogwall) mais je ne pense pas qu'une recherche de style binaire simple serait la meilleure. La raison en est qu'une recherche binaire est basée sur la notion que la réponse que vous recherchez a une chance égale d'être à n'importe quel index d'index de la liste. Cependant, dans ce cas, ce n'est pas vrai. Dans ce cas, la réponse aura une probabilité plus élevée d'être plus proche d'une extrémité de la plage que de l'autre. Je ne sais pas comment intégrer cela dans la recherche, mais c'est une pensée intéressante.


1
Je pense que la question est de demander le meilleur des cas les plus défavorables, donc la distribution n'est pas pertinente tant que chaque étage est possible.
Steve Jessop

-1

tout ce discours fou sur les chats ... et c'est juste une estimation du problème de nombre avec un minimum de suppositions (nombre de chats). il ne devrait pas non plus être nécessaire de définir artificiellement (et incorrectement) l'infini comme faisant partie de la solution. la variable doit avoir été nommée borne supérieure ou max-try ou quelque chose du genre. la définition du problème (le truc du chat) présente cependant de sérieux problèmes, les gens réagissant au potentiel de cruauté envers les animaux et aussi les nombreuses facettes d'un tel problème posé dans la vie réelle, par exemple la traînée d'air, la gravité est l'accélération, et d'autres paramètres de la vie réelle du problème. alors peut-être que cela aurait dû être demandé d'une manière totalement différente.


FWIW, cela peut être un problème déguisé de la vie réelle. Supposons que vous ayez un test automatique qui échoue à la version 1234 mais qui a fonctionné à la version 42. Le chat est mort à 1234 mais vivant à la version 42. Quelle révision l'a tué? Si la mise à jour, par exemple de 42 à 43, est rapide et facile mais que vérifier et reconstruire une nouvelle version est difficile, cela commence à ressembler beaucoup au problème du chat.
mcdowella
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.