Обчисліть ймовірність точно


9

Це завдання стосується написання коду, щоб точно обчислити ймовірність. Вихід повинен бути точною ймовірністю, записаною у вигляді дробу в найбільш скороченому вигляді. Тобто вона ніколи не повинна виводити, 4/8а навпаки 1/2.

Для деякого додатного цілого числа nрозглянемо рівномірно випадковий рядок довжиною 1s та -1s nі назвемо його А. Тепер приєднайтесь до Aсвого першого значення. Тобто A[1] = A[n+1]якщо індексація від 1. Aтепер має довжину n+1. Тепер також розглянемо другий випадковий рядок довжини n, перші nзначення якого становлять -1, 0 або 1 з вірогідністю 1/4,1 / 2, 1/4 кожне і назвемо його B.

Наприклад, розглянемо n=3. Можливі значення для Aі Bможуть бути A = [-1,1,1,-1]і B=[0,1,-1]. У цьому випадку два внутрішні продукти є 0і 2.

Тепер розглянемо внутрішній продукт A[1,...,n]і Bі внутрішній продукт A[2,...,n+1]і B.

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

Бо n=1така ймовірність однозначно 1/2.

Я не заперечую, як nвказано в коді, але це повинно бути дуже простим і очевидним, як це змінити.

Мови та бібліотеки

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


2
Тестові приклади для перших кількох nбули б корисні. Також може допомогти явний приклад A, B та двох внутрішніх продуктів.
Мартін Ендер

Якщо ми вирішимо зафіксувати ціле число, чи n=4зараховується до нуля, двох чи трьох байтів? Чи має бути вихід чи точно, a/b чи [a b], наприклад, буде дозволено?
Денніс

@Dennis Це має бути точним. Якщо ви твердокодуєте ціле число, мені доведеться лише змінити його в одному місці, щоб змінити n? В іншому випадку я думаю, що це не дозволено.

Так, моя програма використовує ціле число лише один раз для обчислення декартової сили. Все інше виводиться з отриманого масиву.
Денніс

Відповіді:


7

Pyth, 48 47 46 44 байт

K,smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q^8Qj\//RiFKK

Спробуйте в Інтернеті: Демонстрація

Інтернет-версія, ймовірно, не обчислює n=6. На моєму ноутбуці (офлайн-версія) це займає близько 45 секунд.

Підхід грубої сили.

Пояснення:

smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q   implicit: Q = input number
                          tM3    the list [-1, 0, 1]
                        +0       add zero, results in [0, -1, 0, 1]
                       ^     Q   all possible lists of length Q using these elements
 m                               map each list d (B in Lembik's notation) to:
                  ,1_1              the list [1, -1]
                 ^    Q             all possible lists of length Q
   f                                filter for lists T (A in Lembik's notation),
                                    which satisfy:
       m        2                      map each k in [0, 1] to:
        s*Vd.>Tk                          scalar-product d*(shifted T by k)
    !|F                                not or (True if both scalar-products are 0)      
  l                                 determine the length                
s                                add all possibilities at the end

K,...^8QQj\//RiFKK   
 ,...^8Q             the list [result of above, 8^Q]
K                    store it in K
              iFK    determine the gcd of the numbers in K
            /R   K   divide the numbers in K by the gcd
         j\/         join the two numbers by "/" and print

dang, забув про gcd, знав, що я щось пропустив
Maltysen

+0r1_2коротше, ніж /R2r2_2.
isaacg

Я вважаю справедливим, це має бути версія 89/512, яку ви рахуєте.

@Lembik Добре змінив.
Якубе

Маю визнати, мені ніколи не спадало на думку, що це можна зробити в 47 символах!

8

Математика, 159 100 87 86 85 байт

n=3;1-Mean@Sign[##&@@Norm/@({1,0,0,-1}~t~n.Partition[#,2,1,1])&/@{1,-1}~(t=Tuples)~n]

Щоб змінити, nпросто змініть визначення змінної на початку.

Оскільки це груба сила, вона досить повільна, але ось перші вісім результатів:

n   P(n)
1   1/2
2   3/8
3   7/32
4   89/512
5   269/2048
6   903/8192
7   3035/32768
8   169801/2097152

Останній вже зайняв 231 секунди, а час виконання жахливо експоненціальний.

Пояснення

Як я вже сказав, це груба сила. По суті, я просто перераховую все можливе Aі Bобчислюю дві крапки добутку для кожної можливої ​​пари, а потім знаходжу частку пар, що вийшли {0, 0}. Комбінаторика Mathematica та функції лінійної алгебри були дуже корисними для цього:

{1,-1}~(t=Tuples)~n

Це створює всі n-кортежі, що містять 1або -1, тобто, всі можливі A. Бо n = 3це:

{{1, 1, 1}, 
 {1, 1, -1}, 
 {1, -1, 1}, 
 {1, -1, -1}, 
 {-1, 1, 1}, 
 {-1, 1, -1}, 
 {-1, -1, 1}, 
 {-1, -1, -1}}

Для обчислення Bми робимо майже те саме:

{1,0,0,-1}~t~n

Повторюючи 0, ми дублюємо кожен кортеж для кожного, який 0він містить, тим самим роблячи 0вдвічі більше, ніж 1або -1. Знову використовуючи n = 3як приклад:

{{-1, -1, -1},
 {-1, -1, 0}, {-1, -1, 0},
 {-1, -1, 1},
 {-1, 0, -1}, {-1, 0, -1},
 {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
 {-1, 0, 1}, {-1, 0, 1},
 {-1, 1, -1},
 {-1, 1, 0}, {-1, 1, 0},
 {-1, 1, 1},
 {0, -1, -1}, {0, -1, -1},
 {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0},
 {0, -1, 1}, {0, -1, 1},
 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
 {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1},
 {0, 1, -1}, {0, 1, -1},
 {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0},
 {0, 1, 1}, {0, 1, 1},
 {1, -1, -1},
 {1, -1, 0}, {1, -1, 0},
 {1, -1, 1},
 {1, 0, -1}, {1, 0, -1},
 {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0},
 {1, 0, 1}, {1, 0, 1},
 {1, 1, -1},
 {1, 1, 0}, {1, 1, 0},
 {1, 1, 1}}

Тепер, для кожного можливого A, ми хочемо крапкового добутку кожного з можливих B, як з, так A[1 .. n]і з A[2 .. n+1]. Наприклад , якщо наш поточний Aє {1, 1, -1}, ми хочемо , щоб скалярний твір з обома {1, 1, -1}і з {1, -1, 1}. Оскільки всі наші Bзручно вже є рядками матриці, ми хочемо, щоб два підлісти були Aстовпцями іншої матриці, щоб ми могли обчислити між ними простий точковий добуток. Але переміщення {{1, 1, -1}, {1, -1, 1}}просто дає, {{1, 1}, {1, -1}, {-1, 1}}що є лише списком усіх двоелементних циклічних підсписів A. Ось що це робить:

Partition[#,2,1,1]

Тож ми обчислимо це і візьмемо крапковий продукт з нашим списком B. Оскільки тепер ми отримуємо вкладений список (оскільки кожен можливий Aвихід окремого вектора), ми вирівнюємо їх ##&@@.

Щоб дізнатися, чи є пара {x, y}, {0, 0}ми обчислюємо, Sign[Norm[{x,y}]] де Normдає √(x²+y²). Це дає 0або 1.

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


6

Pyth - 65 55 байт

Виправлена ​​помилка із зменшенням частки у вартості одного байта.

Використовує грубу силу підходу, і можна пограти в гольф дуже просто, але просто хотів щось дістати. Дуже повільно

*F-KP/Jmms*Vked,thdPhd*makhk^,1_1Q^[1ZZ_1)Q,ZZ2/lJ^2/K2

Він використовує декартові продукти для генерування обох Aі B, виконуючи змінну ймовірність, вносячи 0двічі у список джерел, а потім підраховує ті, що внутрішній добуток, до нуля. Внутрішній продукт Vполегшується синтаксичним цукром екторизації. Спрощення фракції мене спочатку лякало, але це було досить легко за допомогою Pфункції факторизації кільця та усвідомлення того, що нам потрібно лише зменшити потужність 2.

Спробуйте його онлайн тут .


Як я можу змінити n?

@Lembik Програма Pyth запитує введення користувача, яке вказано у другому текстовому полі (Якщо ви використовуєте онлайн-компілятор).
Якубе

@Jakube О, дякую! І насправді, здається, теж працює :)

6

CJam, 58 57 54 51 46 байт

WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__~)&:T/'/@,T/

Щоб запустити його, вставте потрібне ціле число між WX]і m*.

Дякуємо @ jimmy23013 за трохи магії та за те, що гольф на 5 байт!

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Ідея

Більшість частин відповіді відверта, але вона використовує два акуратні хитрощі:

  • Замість того, щоб спаровувати всі вектори {-1, 1} n з усіма векторами {-1, 0, 1} n з бажаними ймовірностями, він вважає підрахунок кількості трійки векторів у {-1, 1} n, які задовольняють певна умова.

    Якщо додати два останніх вектора триплета, результатом буде вектор {-2, 0, 2} n .

    Оскільки (-1) + 1 = 0 = 1 + (-1) , 0 с буде виникати вдвічі частіше, ніж -2 с і 2 с.

    Ділення кожного компонента на 2 дало б вектор {-1, 0, 1} n з бажаними ймовірностями.

    Оскільки нас цікавить лише те, що скалярний продукт дорівнює 0 чи ні, ми можемо пропустити поділ на 2 .

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

    Замість обчислення GCD обох чисел, оскільки знаменник завжди буде потужністю 2, достатньо розділити обидва числа на найвищу потужність 2, яка ділить чисельник.

    Для отримання найвищої потужності на 2, що ділить х , ми можемо взяти порозрядне AND з x і ~ x + 1 .

    ~ x обертає всі біти x , тому всі відстані 0 s стають 1 s. Додавши 1 до ~ х , ці 1 с повернуться назад до 0 с, а останній 1 у ~ х + 1 відповідатиме останньому 1 у х .

    Всі інші біти або обидва 0 різні, тому порозрядне І повертає ціле число, що складається з останнього 1 з x і всіх 0 s, що слідують за ним. Це найвища сила 2, яка ділить х .

Код

WX]    e# Push the array [-1 1].
       e# Insert N here.
m*     e# Cartesian product: Push the array of all vectors of {-1,1}^N.
Zm*    e# Cartesian product: Push the array of all triplets of these vectors.
_      e# Copy the array.
{      e# Filter; for each triplet of vectors U, V and W in {-1,1}^N:
  ~    e#   Dump U, V and W on the stack.
  .+   e#   Compute X := V + W, a vector of {-2,0,2}^N, where each component is
       e#   zero with probability 1/2.
  2,@  e#   Push [0 1]. Rotate U on top of it.
  fm<  e#   Push [U U'], where U' is U rotated one dimension to the left.
  \f.* e#   Push [U*X and U'*X], where * denotes the vectorized product.
  ::+  e#   Add the components of both products.
  0-   e#   Remove zeroes.
       e#   Push the logical NOT of the array.
},     e#   If the array was empty, keep the triplet.
,      e# Push X, the length of the filtered array.
__~)&  e# Push X & ~X + 1.
:T     e# Save the result in T and divide X by T.
'/     e# Push a slash.
@,T/   e# Dividet he length of the unfiltered array by T.

WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__W*&:T/'/@,T/.
jimmy23013

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