Який шанс, що я виграю дверний приз?


12

Мій місцевий глава ОСБ роздає призові двері людям, які приходять на збори. Однак ви отримуєте підвищений шанс виграти, якщо вирішите загадку програмування (але я завжди вирішую цю головоломку). Таким чином, деякі люди мають 1 запис, а інші - 2. Але зачекайте! Те, як працює програма розіграшу, полягає не в тому, щоб додати в інший запис, коли хтось вирішить пазл. Натомість він відслідковує кількість "життів" людини, декрементуючи, що якщо цю особу обирають при кожному пропуску, це алгоритм випадкового відбору. Так воно працює так:

Doorknob: 1.  xnor: 2.  Justin: 2.  Alex: 1.  Dennis: 2.

Тоді програма випадковим чином вибирає один із [Doorknob, xnor, Justin, Alex, Dennis], зменшує число (скажімо, що вибирає Justin):

Doorknob: 1.  xnor: 2.  Justin: 1.  Alex: 1. Dennis: 2.

І повторюється. Якщо чиєсь число "життів" переходить 0(давайте вибираємо Justinще раз), вони видаляються зі списку:

Doorknob: 1.  xnor: 2.  Alex: 1.  Dennis: 2.

Це триває, поки не залишиться одна людина; ця людина є переможцем.

Тепер справжнє питання полягає в тому, якою була ймовірність того, що я виграю?


Вам будуть надані два входи:

  • n. Це кількість людей, які взяли участь у виклику
  • k. Це кількість людей (тих n), які мають 2 життя. Цей номер завжди включає вас.

Тож якби я функціонував pі зателефонував p(10, 5), це була б ймовірність виграти приз, де всього 10 людей, 5 з яких мають лише 1 життя, тоді як 5 (включаючи вас) мають 2 життя.


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

Ваше рішення може бути рандомизованим рішенням, яке виводить відповідь на 4- й десятковий знак з високою ймовірністю . Ви можете припустити, що вбудований RNG, який ви використовуєте, є справді випадковим, і він повинен виводити правильну відповідь принаймні на 90%.

Крім того, ваш код потребує лише роботи n, k <= 1000, хоча я надавав тестові випадки, більші, ніж ті, хто цікавиться.


Випробування

Примітка: деякі з них є загальними формулами.

n,    k   |  output
----------+---------
1,    1   |  1
2,    2   |  0.5
2,    1   |  0.75
3,    1   |  11/18 = 0.611111111
1000, 1   |  0.007485470860550352
4,    3   |  0.3052662037037037
k,    k   |  1/k
n,    1   |  (EulerGamma + PolyGamma[1 + n])/n    (* Mathematica code *)
          |  (γ + ψ(1 + n))/n
10,   6   |  0.14424629234373537
300,  100 |  0.007871966408910648
500,  200 |  0.004218184180294532
1000, 500 |  0.0018008560286627948
---------------------------------- Extra (not needed to be a valid answer)
5000, 601 |  0.0009518052922680399
5000, 901 |  0.0007632938197806958

Для ще кількох перевірок зробіть p(n, 1) * nнаступне:

n     |  output
------+---------
1     | 1
2     | 1.5 
3     | 1.8333333333333335
10    | 2.928968253968254
100   | 5.1873775176396215
-------------------------- Extra (not needed to be a valid answer)
100000| 12.090146129863305

Я більше не знайомий з тегами на цьому сайті; якщо ви думаєте про більш підходящий тег, відредагуйте його!
Джастін

Питання, пов’язані з math.se: math.stackexchange.com/q/1669715/72616
Джастін

Отже, P (n, k) = ((k-1) / n) P (n, k-1) + ((nk) / n) P (n-1, k) + (1 / n) Q ( n, k-1), де Q (n, k) = ((nk-1) / n) Q (n-1, k) + (k / n) Q (n, k-1) і Q (1 , 0) = 1 ...
Лина монашка

@KennyLau Я не збираюся його намагатись інтерпретувати, але остерігайтеся посилання math.se, оскільки він використовує дещо інше визначення функції (я вважаю k, вимкнений одним)
Джастін

2
Чи добре робити рандомізоване моделювання з достатньою кількістю випробувань, щоб відповідь була правильною на четвертий десятковий знак з високою ймовірністю, хоча, звичайно, не напевне?
xnor

Відповіді:


2

MATL , 42 байти

:<~QXJx`J`tf1Zry0*1b(-tzq]f1=vts3e8<]6L)Ym

Для цього використовується ймовірнісний (Монте-Карло) підхід. Експеримент проводиться велика кількість разів, з якого оцінюється ймовірність. Число реалізацій вибирають так, щоб гарантувати , що результат є правильним до четвертого знака після коми з ймовірністю не менше 90%. Однак на це потрібно дуже багато часу та багато пам’яті. На засланні нижче числа реалізацій був зменшений на коефіцієнт 10 6 таким чином , що програма завершується в розумних amout часу; і тільки перша десяткова сума гарантується точністю, щонайменше, на 90%.

EDIT (29 липня 2016 р.): Через зміни мови 6Lйого потрібно замінити на 3L. Посилання нижче містить цю модифікацію.

Спробуйте в Інтернеті!

Фон

Нехай p позначає ймовірність для обчислення. Експеримент, описаний у виклику, буде проведено декілька n разів. Кожен раз ви виграєте приз (« успіх ») або не зробите. Нехай N - кількість успіхів. Бажану ймовірність можна оцінити з N і n . Чим більший n , тим точнішою буде оцінка. Ключовим питанням є те, як вибрати n, щоб виконати потрібну точність, а саме - переконатися, що принаймні у 90% разів помилка буде меншою ніж 10 −4 .

Методи Монте-Карло можуть бути

  • Фіксований розмір : значення n фіксується заздалегідь (і тоді N є випадковим);
  • Змінна величина : n визначається на ходу за результатами моделювання.

Серед другої категорії загальноприйнятим методом є закріплення N (бажана кількість успіхів) та продовження моделювання, поки ця кількість успіхів не буде досягнута . Таким чином n є випадковим. Ця методика, яка називається зворотним біноміальним відбором або негативно-біноміальним Монте-Карло , має перевагу в тому, що точність оцінювача може бути обмежена. З цієї причини він буде використовуватися тут.

Зокрема, з негативно-біноміальним Монте-Карло x = ( N −1) / ( n −1) є неупередженим оцінником p ; і ймовірність того, що x відхилиться від p на більш ніж задане співвідношення, може бути верхньо обмеженою. Згідно рівняння (1) у цій роботі (зауважимо також, що умови (2) виконуються), приймаючи N = 2,75 · 10 8 або більше, гарантує, що p / x належить інтервалу [1.0001, 0.9999] принаймні 90% ймовірність. Зокрема, це означає, що x відповідає правильному розміру до 4-го знаку після коми, принаймні 90% ймовірності, як бажано.

Код пояснено

Код використовує N =, 3e8щоб зберегти один байт. Зауважте, що для цього багато моделювання зайняло б багато часу. Код у посиланні використовує N = 300, який працює за більш розумну кількість часу (менше 1 хвилини в онлайн-компіляторі для перших тестових випадків); але це лише запевняє, що перша десяткова вірна з вірогідністю принаймні 90%.

:        % Take k implicitly. Range [1 ... k]
<~       % Take n implicitly. Determine if each element in the previous array is
         % less than or equal than n
Q        % Add 1. This gives an array [2 ... 2 1 ... 1]
XJx      % Copy to clipboard J. Delete from stack
`        % Do...while. Each iteration is a Monte Carlo realization, until the 
         % desired nunber of successes is reached
  J      %   Push previously computed array [2 ... 2 1 ... 1]
  `      %   Do...while. Each iteration picks one door and decrements it, until
         %   there is only one
    t    %     Duplicate
    f    %     Indices of non-zero elements of array
    1Zr  %     Choose one of them randomly with uniform distribution
    y0*  %     Copy of array with all values set to 0
    1b(  %     Assign 1 to chosen index
    -    %     Subtract
    tzq  %     Duplicate. Number of nonzero elements minus 1. This is falsy if
         %     there was only one nonzero value; in this case the loop is exited
  ]      %   End do...while
  f1=    %   Index of chosen door. True if it was 1 (success), 0 otherwise
  v      %   Concatenate vertically to results from previous realizations
  ts3e8< %   Duplicate. Is the sum less than 3e8? If so, the loop is exited
]        % End do...while
6L)      % Remove last value (which is always 1)
Ym       % Compute mean. This gives (N-1)/(n-1). Implicitly display

Ха-ха, я не усвідомлював, що 90% зробить це так важко :-)
Джастін

Так, четверта десяткова частина з 90% впевненістю - справді вимога :-)
Луїс Мендо

2

Pyth, 34 байти

Mc|!*HJ-GHch*J+*tHgGtH*gtGHKh-GHKG

Тестовий набір

Визначає детерміновану запам'ятовувану рекурсивну функцію, gприймаючи n , k як аргументи. g 1000 500повертається 0.0018008560286627952приблизно за 18 секунд (не входить до складу вищевказаного тестового набору, тому що він вичерпує роботу онлайн-перекладача).

Орієнтовний переклад Python 3 був би

@memoized
def g(n,k):
    return (not k*(n-k) or (1+(n-k)*((k-1)*g(n,k-1)+g(n-1,k)*(n-k+1)))/(n-k+1))/n

1

JavaScript (ES6), 65 байт

f=(n,k,d=n-k)=>(!d||(f(n-1,k)*++d*--d+1+(--k&&f(n,k)*k*d))/++d)/n

Не намагайтеся це все-таки з великою кількістю; навіть f (30, 10) займає помітну кількість часу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.