Викидання котів з вікон


150

Уявіть, що ви знаходитесь у високій будівлі з котом. Кішка може пережити падіння з низького поверху, але загине, якщо її кинуть з високого поверху. Як можна зрозуміти найдовшу краплю, яку кішка може пережити, використовуючи найменшу кількість спроб?

Очевидно, що у вас є лише одна кішка, ви можете шукати лише лінійно. Спочатку киньте кота з першого поверху. Якщо вона виживе, киньте її з другої. Врешті-решт, після того, як його скинуть з підлоги f, кішка загине. Тоді ви знаєте, що підлога f-1 була максимально безпечною підлогою.

Але що робити, якщо у вас більше однієї кішки? Тепер ви можете спробувати якийсь логарифмічний пошук. Скажімо, що у будівлі 100 поверхів, а у вас дві однакові коти. Якщо ви викинете першу кішку з 50-го поверху і вона помирає, то вам доведеться лише шукати 50 поверхів лінійно. Ви можете зробити ще краще, якщо для своєї першої спроби виберете нижній поверх. Скажімо, ви вирішили вирішити проблему 20 поверхів одночасно і що перший фатальний поверх - №50. У такому випадку ваша перша кішка переживе польоти з 20 та 40 поверхів, перш ніж померти з поверху 60. Вам потрібно лише перевірити поверхи від 41 до 49 окремо. Це в цілому 12 спроб, що набагато краще, ніж 50, які вам знадобляться, якби ви намагалися використати бінарне усунення.

Загалом, яка найкраща стратегія та найгірша складність для n-поверхової будівлі з двома котами? А як щодо п яти поверхів і м котів?

Припустимо, що всі коти рівноцінні: всі вони виживуть або помруть від падіння з заданого вікна. Також кожна спроба є незалежною: якщо кішка переживе падіння, вона цілком неушкоджена.

Це не домашнє завдання, хоча я, можливо, колись вирішив це для шкільного завдання. Це просто примхлива проблема, яка сьогодні впала мені в голову, і я не пам'ятаю рішення. Бонусні бали, якщо хтось знає назву цієї проблеми або алгоритм рішення.


123
Я заперечую проти використання котів описаним чином. Чи можемо ми змінити це на собак?
Тіло

53
Це не так просто. Проведено дослідження (котів, які випадково випадають з хмарочосів, не кидають). Там, де вони загинули, був певний діапазон ***, і діапазон *** вище, ніж цей ***, де вони вижили. Щось про те, як вони напружували свої тіла.
Андрій Пастух

5
Я десь читав, що 15 футів або вище, у котів більший шанс вижити. Це питання краще підійде, якби ми відкидали колишніх подруг та / або набридли дружин.
Ентоні Форлоні

34
Ви знаєте, що якщо ви почнете з двох котів, ви можете просто почекати кілька місяців, а потім запустити двійковий пошук. Або зачекайте кілька місяців після цього і зробіть "одночасний пошук", коли ви отримуєте помічників одночасно викидати котів з кожного поверху - кількість вижилих котів у цьому випадку - це найбільший номер поверху, з якого ви, звичайно, можете їх викинути. .
mjfgates

10
З зайчиками поміняйте "місяці" на "тижні".
mjfgates

Відповіді:


70

Ви можете легко написати трохи DP (динамічне програмування) для загального випадку n поверхів і м котів.

Основна формула, 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.

Він погоджується з результатом Google із посилання Гаурава Саксени на (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]);

Ви можете легко знайти стратегію (як кинути першого кота), якщо найкраще збережете kв іншому масиві.

Існує також більш швидке рішення, що не включає обчислення O (n ^ 3), але я вже трохи сонний.

редагувати
О так, я пам'ятаю, де я бачив цю проблему раніше .


Хм, чи не + 1потрібно бути поза min()? Як ви самі кажете, спроба успішна чи ні, це все ж спроба.
j_random_hacker

@j_random_hacker Чи це щось змінить? Переїзд +1за межі min. Або перемістити його всередину max:)
Микита Рибак

@Nikita: Вибачте, я якось неправильно прочитав те, що ви написали - те, що ви маєте, по-моєму правильно! +1.
j_random_hacker

Зауважте, що це ідентично "Проблемі викидання яєць Google Code Jam".
Наведене

1
Дивіться це нове запитання щодо алгоритму O (n). Найвища відповідь на Google Code Jam - це O (n), але я її ще не розумію. stackoverflow.com/questions/4699067 / ...
ripper234

92

Згідно з останнім епізодом Radiolab (про "Падіння") , кіт досягає кінцевої швидкості до 9-го поверху. Після цього вона розслабляється і рідше болить. Є абсолютно не пошкоджені коти після падіння зверху 30-го. Найризикованіші поверхи - 5-й по 9-й.


16
Як людина з котами, я хотів би зазначити, що це дослідження ґрунтувалося на повідомленнях лікарні для тварин після інцидентів денестрації. Жодні додаткові коти не отримали поранень чи незручностей у цьому запиті.
Тіло

16
Не відповідь, а лише якийсь додатковий контекст з бізнес-сфери.
Тіло

19
Це стільки ж відповіді, скільки заслуговує питання.
Марк Рансом

2
Це просто показує, як це не випадок live = 1, die = 0 як результат, але більше live = 1.0, die = 0.0 і все, що знаходиться між ними, - це ймовірності. Це також крива, а не лінія, яку потрібно виявити.
тадман

73
Проблема з цим звітом полягає в ухилі відбору - ніхто не везе мертву кішку до ветеринара.
Нікі Йошіучі

10

Уявіть, що ви знаходитесь у високій будівлі з котом. Кішка може пережити падіння з низького поверху, але загине, якщо її кинуть з високого поверху. Як можна зрозуміти найдовшу краплю, яку кішка може пережити, використовуючи найменшу кількість спроб?

Найкращою стратегією вирішення цієї проблеми є дослідження, використовуючи закон фізики, в першу чергу вірогідність ваших припущень.

Якби ви зробили це, ви зрозуміли б, що шанси кота на виживання насправді збільшуються, чим більша відстань до землі. Звичайно, якщо припустити, що ви викидаєте його з все більш високої будівлі, наприклад, з веж петрони, а не з більш високої гори, як, наприклад, гора Еверест.

Редагувати:
насправді ви побачите незавершений розподіл верблюдів.
Спочатку ймовірність того, що кішка загине, мала (дуже низька висота), потім вона стає більшою (низька висота), потім знову нижчою (більша висота), а потім знову більшою (дуже велика висота).

Графік вірогідності загибелі кота як функції висоти над землею виглядає приблизно так:
(закінчити в 3, оскільки незавершений розподіл верблюдів)

alt текст

Оновлення:
кінцева кінцева швидкість - 100 км / год (60 миль / год) [= 27,7 м / с = 25,4 ярдів / с].
Кінцева швидкість людини становить 210 км / год (130 м / год). [= 75 м / с = 68,58 ярдів / с]

Джерело швидкості на терміналі:
http://en.wikipedia.org/wiki/Cat_righting_reflex

Кредити:
goloogle

Мені потрібно перевірити пізніше:
http://en.wikipedia.org/wiki/Terminal_velocity
http://www.grc.nasa.gov /WWW/K-12/airplane/termv.html



2
Це правильно? Звичайно, коли термінальна швидкість буде досягнута, шанси не можуть змінитися - і я був під враженням, що кішка може пережити падіння термінальної швидкості.
ZoFreX

4
@ZoFreX: Впевнені, що можуть, саме нижча кінцева швидкість є найбільш фатальною. З іншого боку, киньте кішку з, скажімо, на сто тисяч миль вгору, і кішка швидше згоряє в атмосфері після смерті від вакууму, ніж падає і живе.
Девід Торнлі

1
Чи є в цьому графі ті вуха зайчика?
ніндзя

1
@ZoFreX: Кут імпульсу. Кішка завжди приземляється на ноги, через кутовий імпульс через конструкцію тіла кота та навички повороту кота. Але це все ще означає, що для обертання потрібен час. Чим більше часу буде (==> чим більша висота), тим більше шансів на те, що кішка приземлиться на ноги (==> шанси на виживання різко зростуть, на відміну, наприклад, від посадки на голову). Але ви маєте рацію, ймовірність залишається тією ж, після досягнення кінцевої швидкості. Я б сказав, що цілком ймовірно, що кішка може пережити падіння швидкості на терміналі, принаймні міна вискочила у вікно ванної кімнати (приблизно 20 м), без подряпин.
Стефан Штайгер

8

Я вперше прочитав цю проблему в Посібнику з алгоритму Стівена Скіени (вправа 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)?

Всього 1 яйце

Викидання яйце з кожного поверху, починаючи з першого, знайде критичну підлогу в (в гіршому випадку) n операціях.

Більш швидкого алгоритму немає. У будь-який час у будь-якому алгоритмі нехай г найвищий поверх, з якого було видно яйце, не зламається. Алгоритм повинен перевірити поверх g + 1 перед будь-яким вищим поверхом h> g + 1, інакше якби яйце було відірване від підлоги h, воно не могло б розрізнити f = g + 1 і f = h.

2 яйця

Спочатку розглянемо випадок k = 2 яєць, коли n = r ** 2 - досконалий квадрат. Ось стратегія, яка займає час O (sqrt (n)). Почніть з опускання першого яйця з кроком r поверхів. Коли перше яйце ламається, скажімо, на підлозі ar, ми знаємо, що критична підлога повинна бути (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-яйце. КОНТРАЦІЯ.

k яйця

Алгоритм, представлений для 2 яєць, може бути легко розширений до k яєць. Викидайте кожне яйце з постійними інтервалами, які слід сприймати як повноваження k-го кореня n. Наприклад, для n = 1000 і k = 3, інтервали пошуку 100 поверхів з першим яйцем, 10 з другим яйцем і 1 з останнім яйцем.

Аналогічно, ми можемо довести, що жоден алгоритм не є швидшим Θ(n**(1/k)), індукуючи доказ k = 2.

Точне рішення

Ми виводимо повтор, оптимізуючи, куди потрібно скинути перше яйце (підлога g), припускаючи, що ми знаємо оптимальні рішення для менших параметрів. Якщо яйце зламається, ми маємо g-1 поверхи нижче, щоб вивчити яйця k-1. Якщо яйце виживе, ми маємо поверхи вище, щоб досліджувати 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

2

Це не передбачає, що ви використовуєте "Той самий кіт"?

Ви можете підійти до нього математично, але це приємна річ у математиці ... за правильних припущень 0 може дорівнювати 1 (для великих значень 0).

З практичної точки зору, ви можете отримати "Подібні кішки", але ви не можете отримати "Той самий кіт".

Ви можете спробувати визначити відповідь емпіричним шляхом, але я думаю, що буде достатньо статистичних відмінностей, щоб відповідь була статистично безглуздою.

Ви можете спробувати ВИКОРИСТИТИ "Той самий кіт", але це не вийшло, оскільки після першої краплі це вже не той самий кіт. (Подібно до того, хтось ніколи не може двічі ступати в одну річку)

Або ви могли зібрати здоров'я кота, взявши проби через надзвичайно близькі проміжки часу, і знайти ті висоти, для яких кішка "здебільшого жива" (на відміну від "переважно мертвих" від "нареченої принцеси"). Коти в середньому виживуть (до останнього інтервалу).

Я думаю, що я відмовився від початкового наміру, але якщо ви рухаєтесь емпіричним шляхом, я голосую за те, щоб почати якомога вище і продовжувати скидати котів, оскільки зріст зменшується, поки вони статистично не виживуть. А потім перевірте тест на вижилих котів, щоб бути впевненим.


0

Я взяв дещо інший метод отримання розчину.

Я почав з розробки максимального поверху, який можна було б покрити за допомогою x котів та y здогадок, використовуючи наступний метод.

Почніть з 1 поверху і продовжуйте збільшувати кількість здогадок, одночасно відслідковуючи перевірені підлоги, які здогадки про них перевіряли і скільки котів залишилось на кожному поверсі.
Повторіть це до у разів.

Цей дуже неефективний код для обчислення даної відповіді, але, тим не менш, корисний для невеликої кількості котів / поверхів.

Код 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 відповідають комбінованому кусочно.

Для 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 (завдяки роботам blogwall), але не думаю, що прямий пошук у бінарному стилі був би найкращим. Причина полягає в тому, що двійковий пошук базується на уявленні, що відповідь, яку ви шукаєте, має однакові шанси опинитися в будь-якому індексі в списку. Однак у цьому випадку це неправда. У цьому випадку відповідь матиме більшу ймовірність бути ближче до одного кінця діапазону, ніж до іншого. Я поняття не маю, як це зробити в пошуку, але це цікава думка.


1
Я думаю, що питання задає найкращий гірший випадок, тому розподіл не має значення, поки можливий кожен поверх.
Стів Джессоп

-1

все це божевільна розмова про котів .. і це лише здогадка про чисельність проблеми з мінімальними здогадами (кількість котів). також не повинно бути штучним (і неправильно) визначати нескінченність як частину рішення. змінна повинна була бути названа верхньою межею, або макс-спробувати, або якась така. Визначення проблеми (котяча річ) має деякі серйозні проблеми, хоча люди реагують на потенціал жорстокості до тварин, а також багато аспектів такої проблеми, що виникають у реальному житті, наприклад, вологостійкість, гравітація є прискоренням та інші такі реальні параметри життя проблеми. тому, можливо, це слід було б запитати зовсім по-іншому.


FWIW це може бути замаскована реальна життєва проблема. Припустимо, у вас є автоматичний тест, який не працює у версії 1234, але працював у версії 42. Кіт мертвий у 1234 році, але живе у версії 42. Яка редакція вбила його? Якщо оновлення, наприклад, з 42 до 43, швидко і легко, але перевірка та відновлення нової версії є важким, це починає виглядати як проблема кота.
mcdowella
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.