Gettare i gatti fuori dalle finestre


150

Immagina di essere in un edificio alto con un gatto. Il gatto può sopravvivere a una caduta da una finestra bassa, ma morirà se lanciato da un piano alto. Come puoi capire la goccia più lunga che il gatto può sopravvivere, usando il minor numero di tentativi?

Ovviamente, se hai un solo gatto, puoi cercare solo linearmente. Prima lancia il gatto dal primo piano. Se sopravvive, lancialo dal secondo. Alla fine, dopo essere stato gettato dal pavimento f, il gatto morirà. Allora sai che il piano f-1 era il piano massimo sicuro.

E se avessi più di un gatto? Ora puoi provare una sorta di ricerca logaritmica. Diciamo che la build ha 100 piani e hai due gatti identici. Se lanci il primo gatto fuori dal 50 ° piano e muore, devi solo cercare 50 piani in modo lineare. Puoi fare ancora meglio se scegli un piano inferiore per il tuo primo tentativo. Diciamo che hai scelto di affrontare il problema 20 piani alla volta e che il primo piano fatale è il numero 50. In tal caso, il tuo primo gatto sopravviverà ai voli dai piani 20 e 40 prima di morire dal piano 60. Devi solo controllare i piani da 41 a 49 individualmente. Sono in totale 12 i tentativi, che è molto meglio dei 50 di cui avresti bisogno se avessi tentato di usare l'eliminazione binaria.

In generale, qual è la strategia migliore e la complessità peggiore per un edificio a due piani con 2 gatti? Che dire di n piani e m gatti?

Supponiamo che tutti i gatti siano equivalenti: sopravviveranno o moriranno da una caduta da una determinata finestra. Inoltre, ogni tentativo è indipendente: se un gatto sopravvive a una caduta, è completamente illeso.

Non si tratta di compiti a casa, anche se potrei averlo risolto per un incarico scolastico una volta. È solo un problema stravagante che mi è saltato in testa oggi e non ricordo la soluzione. Punti bonus se qualcuno conosce il nome di questo problema o dell'algoritmo della soluzione.


123
Mi oppongo all'uso dei gatti nel modo descritto. Possiamo cambiarlo in cani?
Thilo,

53
Non è così semplice. Sono stati fatti studi (sui gatti che cadono accidentalmente dai grattacieli, senza essere lanciati). C'era un certo intervallo in cui morirono e un intervallo *** superiore a questo *** in cui sopravvissero. Qualcosa su come hanno teso i loro corpi.
Andrew Shepherd,

5
Ho letto da qualche parte che a 15 piedi o più, i gatti hanno maggiori possibilità di sopravvivere. Questa domanda sarebbe più adatta se abbandonassimo ex fidanzate e / o fastidiose mogli.
Anthony Forloney,

34
Sai, se inizi con due gatti, POTREBBE solo aspettare qualche mese e quindi eseguire una ricerca binaria. Oppure attendi qualche mese dopo e fai una "ricerca simultanea", in cui ottieni aiutanti a lanciare gatti da ogni piano contemporaneamente - il numero di gatti sopravvissuti in quel caso è il numero di piano più alto da cui puoi lanciarli, ovviamente .
mjfgates,

10
Con i coniglietti, cambia "mesi" in "settimane".
mjfgates,

Risposte:


70

Puoi facilmente scrivere un po 'di DP (programmazione dinamica) per il caso generale di n piani e gatti.

La formula principale a[n][m] = min(max(a[k - 1][m - 1], a[n - k][m]) + 1) : for each k in 1..n, dovrebbe essere autoesplicativa:

  • Se il primo gatto viene lanciato dal k-esimo piano e muore, ora abbiamo i k - 1piani da controllare (tutti sotto k) e i m - 1gatti ( a[k - 1][m - 1]).
  • Se il gatto sopravvive, ci sono ancora n - kpiani (tutti i piani sopra k) e ancora mgatti.
  • Il caso peggiore di due dovrebbe essere scelto, quindi max.
  • + 1 deriva dal fatto che abbiamo appena usato un tentativo (indipendentemente dal fatto che il gatto sia sopravvissuto o meno).
  • Proviamo ogni possibile piano per trovare il risultato migliore, quindi min(f(k)) : for k in 1..n.

È d'accordo con il risultato di Google dal link di Gaurav Saxena per (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]);

Puoi facilmente trovare la strategia (come lanciare il primo gatto), se risparmi meglio kin un altro array.

C'è anche una soluzione più veloce, che non prevede calcoli O (n ^ 3), ma ho già un po 'di sonno.

modifica
Oh sì, ricordo dove ho visto questo problema prima .


Hmm, non è + 1necessario essere al di fuori del min()? Come dici tu stesso, che il tentativo abbia successo o meno, è ancora un tentativo.
j_random_hacker,

@j_random_hacker Cambia qualcosa? Muoversi +1al di fuori di min. O spostandolo all'interno di max:)
Nikita Rybak,

@Nikita: mi dispiace di aver frainteso in qualche modo quello che avevi scritto - quello che hai è esattamente secondo me! +1.
j_random_hacker,

Nota che questo è identico al "Problema di rilascio delle uova" di Google Code Jam. La soluzione O (n ^ 3) di seguito non è abbastanza buona, perché il set di problemi di grandi dimensioni utilizza N = 2000000000. code.google.com/codejam/contest/dashboard?c=32003#s=p2
ripper234

1
Vedi questa nuova domanda per un algoritmo O (n). La risposta migliore a Google Code Jam è O (n), ma non l'ho ancora capito. stackoverflow.com/questions/4699067/...
ripper234

92

Secondo un recente episodio di Radiolab (su "Falling") , un gatto raggiunge la velocità terminale al nono piano. Successivamente, si rilassa ed è meno probabile che si faccia male. Ci sono gatti completamente non feriti dopo una caduta da sopra il 30. I piani più rischiosi sono dal 5 al 9 °.


16
Come persona di gatto, vorrei sottolineare che questo studio si basava su segnalazioni di animali ospedalieri dopo incidenti di defenestrazione. Nessun ulteriore gatto è stato ferito o disturbato in questa inchiesta.
Thilo,

16
Non una risposta, solo qualche ulteriore contesto dal dominio aziendale.
Thilo,

19
È tanto una risposta quanto la domanda merita.
Mark Ransom,

2
Questo dimostra come non sia un caso di live = 1, die = 0 come risultato, ma più di live = 1.0, die = 0.0 e tutto ciò che sta nel mezzo è probabilità. È anche una curva, non una linea, che deve essere scoperta.
Tadman,

73
Il problema con quel rapporto è il pregiudizio alla selezione: nessuno porta un gatto morto dal veterinario.
Niki Yoshiuchi,

10

Immagina di essere in un edificio alto con un gatto. Il gatto può sopravvivere a una caduta da una finestra bassa, ma morirà se lanciato da un piano alto. Come puoi capire la goccia più lunga che il gatto può sopravvivere, usando il minor numero di tentativi?

La migliore strategia per risolvere questo problema è investigare, usando la legge della fisica, la probabilità che le tue ipotesi siano vere in primo luogo.

Se lo avessi fatto, ti accorgeresti che le possibilità di sopravvivenza del gatto aumentano effettivamente quanto più alta è la distanza dal suolo. Naturalmente, supponendo che lo lanciate da un edificio sempre più alto, come le torri Petronas, e non da una montagna sempre più alta, come il monte Everest.

Modifica: in
realtà, vedresti una distribuzione di cammelli incompiuta.
Innanzitutto, la probabilità che il gatto muoia è bassa (altitudine molto bassa), quindi aumenta (bassa altitudine), quindi di nuovo più bassa (altitudine più elevata) e quindi di nuovo più alta (altitudine molto elevata).

Il grafico per la probabilità che il gatto muoia in funzione dell'altitudine sopra il suolo è simile al seguente:
(finire a 3, perché la distribuzione del cammello non è finita)

testo alternativo

Aggiornamento:
la velocità terminale di un gatto è 100 km / h (60 mph) [= 27,7 m / s = 25,4 iarde / s].
La velocità del terminale umano è di 210 km / h (130 mph). [= 75m / s = 68.58 iarde / s]

Fonte velocità terminale:
http://en.wikipedia.org/wiki/Cat_righting_reflex

Crediti:
Goooooogle

Devo verificare in seguito:
http://en.wikipedia.org/wiki/Terminal_velocity
http://www.grc.nasa.gov /WWW/K-12/airplane/termv.html



2
È corretto? Sicuramente una volta raggiunta la velocità terminale, le possibilità non possono cambiare - e avevo l'impressione che un gatto potesse sopravvivere a una caduta di velocità terminale.
ZoFreX,

4
@ZoFreX: Certo che possono, è la velocità terminale appena sotto la più fatale. D'altra parte, lascia cadere un gatto da, diciamo centomila miglia in su, e il gatto ha più probabilità di bruciarsi nell'atmosfera dopo essere morto dal vuoto che cadere e vivere.
David Thornley,

1
Quelle orecchie da coniglio sono in quel grafico?
ninjalj,

1
@ZoFreX: momento angolare. Un gatto atterra sempre in piedi, a causa del momento angolare a causa del design del corpo del gatto e delle sue abilità di svolta. Ma ciò significa ancora che ha bisogno di tempo per girare. Maggiore è il tempo (==> maggiore è l'altitudine), maggiore è la probabilità che il gatto atterri in piedi (==> le probabilità di sopravvivenza aumentano notevolmente, rispetto ad esempio all'atterraggio sulla testa). Ma hai ragione, la probabilità rimane la stessa dopo aver raggiunto la velocità terminale. Direi che è molto probabile che un gatto possa sopravvivere a una caduta di velocità terminale, almeno il mio è saltato fuori dalla finestra del bagno (circa 20 m), senza un graffio.
Stefan Steiger,

8

Ho letto per la prima volta questo problema nel Manuale di progettazione degli algoritmi di Steven Skiena (esercizio 8.15). Ha seguito un capitolo sulla programmazione dinamica, ma non è necessario conoscere la programmazione dinamica per dimostrare limiti precisi alla strategia . Prima la dichiarazione del problema, quindi la soluzione seguente.

Le uova si rompono quando lasciate cadere da un'altezza abbastanza grande. Dato un edificio n-story, ci deve essere un piano f tale che le uova cadute dal piano f si rompano, ma le uova cadute dal piano f-1 sopravvivono. (Se l'uovo si rompe da qualsiasi piano, diremo f = 1. Se l'uovo sopravvive da qualsiasi piano, diremo f = n + 1).

Cerchi di trovare il piano critico f. L'unica operazione che puoi eseguire è far cadere un uovo dal pavimento e vedere cosa succede. Inizi con k uova e cerchi di far cadere le uova il meno volte possibile. Le uova rotte non possono essere riutilizzate (le uova intatte possono). Sia E (k, n) il numero minimo di escrementi di uova che sarà sempre sufficiente.

  1. Mostra che E (1, n) = n.
  2. Dimostralo E(k,n) = Θ(n**(1/k)).
  3. Trova una ricorrenza per E (k, n). Qual è il tempo di esecuzione del programma dinamico per trovare E (k, n)?

Solo 1 uovo

Far cadere l'uovo da ogni piano a partire dal primo troverà il pavimento critico in (nella peggiore delle ipotesi) n operazioni.

Non esiste un algoritmo più veloce. In qualsiasi momento in qualsiasi algoritmo, lascia g il piano più alto da cui è stato visto l'uovo non rompersi. L'algoritmo deve testare il piano g + 1 prima di qualsiasi piano superiore h> g + 1, altrimenti se l'uovo dovesse rompersi dal piano h, non potrebbe distinguere tra f = g + 1 e f = h.

2 uova

Innanzitutto, consideriamo il caso k = 2 uova, quando n = r ** 2 è un quadrato perfetto. Ecco una strategia che richiede tempo O (sqrt (n)). Inizia facendo cadere il primo uovo con incrementi di r piani. Quando il primo uovo si rompe, diciamo al piano ar, sappiamo che il piano critico f deve essere (a-1)r < f <= ar. Lasciamo quindi cadere il secondo uovo da ogni piano a partire da (a-1)r. Quando il secondo uovo si rompe, abbiamo trovato il piano critico. Abbiamo lasciato cadere ogni uovo al massimo r, quindi questo algoritmo prende le peggiori operazioni 2r, che è which (sqrt (n)).

Quando n non è un quadrato perfetto, prendi r = ceil(sqrt(n)) ∈ Θ(sqrt(n)) . L'algoritmo rimane Θ (sqrt (n)).

Prova che qualsiasi algoritmo richiede almeno sqrt (n) tempo. Supponiamo che esista un algoritmo più veloce. Considera la sequenza di piani da cui fa cadere il primo uovo (purché non si rompa). Dato che scende meno di sqrt (n), deve esserci un intervallo di almeno n / sqrt (n) che è sqrt (n). Quando f è in questo intervallo, l'algoritmo dovrà investigarlo con il secondo uovo, e questo deve essere fatto piano per piano ricordando il caso di 1 uovo. CONTRADDIZIONE.

k uova

L'algoritmo presentato per 2 uova può essere facilmente esteso a k uova. Lascia cadere ogni uovo a intervalli costanti, che dovrebbero essere presi come i poteri della kth radice di n. Ad esempio, per n = 1000 e k = 3, cerca intervalli di 100 piani con il primo uovo, 10 con il secondo uovo e 1 con l'ultimo uovo.

Allo stesso modo, possiamo dimostrare che nessun algoritmo è più veloce Θ(n**(1/k))inducendo dalla dimostrazione k = 2.

Soluzione esatta

Deduciamo la ricorrenza ottimizzando dove far cadere il primo uovo (piano g), presumendo di conoscere soluzioni ottimali per parametri più piccoli. Se l'uovo si rompe, abbiamo i piani g-1 sottostanti da esplorare con le uova k-1. Se l'uovo sopravvive, abbiamo ng piani sopra da esplorare con k uova. Il diavolo sceglie il peggio per noi. Quindi per k> 1 la ricorrenza

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

Se ho k uova, perché il runtime non è O(k*n**(1/k))il caso peggiore? Dal momento che nel peggiore dei casi devo passare n**(1/k) esattamente i ktempi.
Rakete1111,

2

Questo non presuppone che tu stia usando "Lo stesso gatto"?

Puoi affrontarlo matematicamente, ma questa è la cosa bella della matematica ... con i presupposti giusti, 0 può essere uguale a 1 (per grandi valori di 0).

Da un punto di vista pratico, puoi ottenere "Gatti simili", ma non puoi ottenere "Lo stesso gatto".

Potresti provare a determinare empiricamente la risposta, ma penso che ci sarebbero abbastanza differenze statistiche che la risposta sarebbe statisticamente insignificante.

Potresti provare a UTILIZZARE "Lo stesso gatto", ma non funzionerebbe, poiché, dopo la prima caduta, non è più lo stesso gatto. (Allo stesso modo, onecan non entra mai nello stesso fiume due volte)

Oppure, potresti aggregare la salute del gatto, campionando a intervalli estremamente ravvicinati, e trovare le altezze per le quali il gatto è "per lo più vivo" (al contrario di "per lo più morto" da "La principessa sposa"). I gatti sopravviveranno, in media (fino all'ultimo intervallo).

Penso di essermi allontanato dall'intento originale, ma se stai seguendo la strada empirica, voto per iniziare il più in alto possibile e continuare a far cadere i gatti quando l'altezza diminuisce fino a quando non sopravvivono statisticamente. E poi riprovare sui gatti sopravvissuti per essere sicuri.


0

Ho preso un metodo leggermente diverso per produrre una soluzione.

Ho iniziato elaborando il piano massimo che potrebbe essere coperto usando x gatti e y ipotesi usando il seguente metodo.

Inizia con 1 piano e continua ad aumentare il numero di supposizioni mantenendo traccia dei piani controllati, che indovinano che sono stati controllati e quanti gatti rimanevano per ogni piano.
Ripeti fino a y volte.

Questo molto codice inefficiente per calcolare la risposta data, ma comunque utile per un piccolo numero di gatti / piani.

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

Per 2 gatti il ​​numero massimo di piani identificabili in x ipotesi è:
1, 3, 6, 10, 15, 21, 28 ...

Per 3 gatti:
1, 3, 7, 14, 25, 41, 63 ...

Per 4 gatti:
1, 3, 7, 15, 30, 56, 98 ...

Dopo una ricerca approfondita (che coinvolge principalmente la digitazione di sequenze di numeri in OEIS ) ho notato che i piani massimi per x seguono uno schema a tratti di combinazione .

Per 2 gatti:
n <2: 2 ^ n - 1
n> = 2: C (n, 1) + C (n, 2)

Per 3 gatti:
n <3: 2 ^ n - 1
n> = 3: C (n, 1) + C (n, 2) + C (n, 3)

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

Da qui ho preso l'approccio semplice dell'incremento semplice n fino a quando ho superato il numero richiesto di piani.

Codice 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

Questo fornisce la soluzione corretta per (100, 2) = 14.
Per chiunque desideri controllare qualcosa di meno banale, dà (1 000 000, 5) = 43.

Questo funziona in O (n) dove n è la risposta al problema (più gatti meglio è).
Comunque sono sicuro che qualcuno con un livello superiore di matematica potrebbe semplificare le formule a tratti per calcolare in 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

Non riesco a leggere il blogspot di Google su questo (grazie a blogwall di lavori) ma non penso che una ricerca diretta in stile binario sarebbe la migliore. Il motivo è che una ricerca binaria si basa sull'idea che la risposta che stai cercando ha le stesse possibilità di trovarsi in qualsiasi indice dell'indice nell'elenco. Tuttavia, in questo caso ciò non è vero. In questo caso la risposta avrà una maggiore probabilità di essere più vicina a un'estremità dell'intervallo rispetto all'altra. Non ho idea di come includerlo nella ricerca, ma è un pensiero interessante.


1
Penso che la domanda stia ponendo il caso peggiore, quindi la distribuzione è irrilevante fintanto che ogni piano è possibile.
Steve Jessop,

-1

tutta questa folle chiacchierata sui gatti ... ed è solo un'ipotesi del problema del numero con ipotesi minime (numero di gatti). non dovrebbe essere necessario definire artificialmente (e in modo errato) l'infinito come parte della soluzione. la variabile avrebbe dovuto essere denominata limite superiore o max-try o qualcosa del genere. la definizione del problema (la cosa del gatto) ha alcuni seri problemi, con le persone che rispondono al potenziale di crudeltà verso gli animali e anche le molte sfaccettature di un tale problema posto nella vita reale, ad esempio il trascinamento dell'aria, la gravità è l'accelerazione e altri parametri simili nella vita reale del problema. quindi forse avrebbe dovuto essere chiesto in un modo completamente diverso.


FWIW potrebbe essere un problema di vita reale mascherato. Supponiamo di avere un test automatico che fallisce alla versione 1234 ma ha funzionato alla versione 42. Il gatto è morto alla 1234 ma vive alla versione 42. Quale revisione l'ha ucciso? Se l'aggiornamento, ad esempio da 42 a 43, è rapido e semplice, ma il check-out e la ricostruzione di una nuova versione sono difficili, questo inizia ad assomigliare molto al problema del gatto.
mcdowella,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.