Вероятности нокаута

9

Knockout - баскетбольная игра, в которой игроки по очереди стреляют. Это играется как последовательность соревнований двух игроков, каждый из которых имеет возможность «выбить» одного из этих игроков.

Предположим, что игроки имеют A B C Dсвои шансы на то, чтобы забить и сделать корзину 0.1 0.2 0.3 0.4соответственно, независимо от другого игрока в конкурсе. Два игрока в начале линии, Aи B, «бой». Так как Aидет первым, он является защитником , в опасности быть устранены, и Bявляется злоумышленником , а не в опасности немедленной ликвидации. Aстреляет первым. Если Aделает это, Aуспешно защитился, и идет в конец линии. Линия изменится на B C D A. Если Aне получится, то Bстреляет. Если Bделает это, то Aвыходит и Bпереходит в конец строки, поэтому линия становится C D B. Если ниAни Bделает это, процесс повторяется с Aсъемкой снова, пока либо Aили Bделает корзинку.

Предположим, линия изменилась на B C D A( Aуспешно защищена). Теперь Bи C«борись» с Bтем, чтобы быть защитником и Cбыть нападающим. Этот процесс повторяется до тех пор, пока не останется только один человек. Этот человек является победителем.

Ваша задача - подсчитать вероятности того, что каждый человек выиграет, если у него будет шанс сделать корзину.

Вход :

Список чисел, например 0.1 0.2или 0.5 0.5 0.5 0.5, где n- й номер - это вероятность того, что n- й игрок соберет корзину. Вы можете использовать этот ввод в любом формате, который вам нравится, в том числе в качестве параметров функции.

Выход :

Список чисел, где n- й номер - это шанс того, что n- й игрок выиграет игру. Ваши числа должны быть точными, по крайней мере, до двух знаков после запятой, по крайней мере, в 90% случаев. Это означает, что вы можете использовать подход, основанный на моделировании. Однако, если ваш код не основан на симуляции ( гарантированно верный ответ будет хотя бы на 6 знаков после запятой), тогда заберите 30% от вашего результата.

Пример между 0.5 0.5: Позвоните игрокам Aи B. Позвольте pбыть вероятность выигрыша. Aимеет 2/3шанс на успешную защиту (так как есть 1/2шанс, который Aзабивает, 1/4шанс, который Aпропускает и Bзабивает, и 1/4шанс, что и промах, и процесс повторяется). Если Aне сможет защитить, он нокаутируется и Bпобеждает. Если Aзащищает, то линия становится B A. Поскольку ситуация симметрична, вероятность Aвыигрыша равна (1 - p). Мы получили:

p = 2/3 * (1 - p) + 1/3 * 0, Решая, мы получаем p = 2/5. Выход должен быть 2/5 3/5или 0.4 0.6.

Я не достаточно хорош с вероятностью делать более сложные примеры.

Если вам нужно больше тестов, вот несколько из них:

0.1 0.2 0.3 0.4 --> 0.01 0.12 0.25 0.62
0.99 0.99 --> 0.5 0.5 (it's not exact, but if you round to two decimal places, you get 0.5 and 0.5)
soktinpk
источник

Ответы:

4

CJam ( 84 80 символов * 0,7 = 56)

{_,({_,,{_2$m<(;(+Q0\)\++m>\}%)_(+.{X2$-*_@+/}1\{1$*\1$-}%)1\-f/.f*:.+}{,da}?}:Q

Демо онлайн . Это рекурсивная функция, которая принимает массив значений типа double и возвращает массив значений типа double. Онлайновая демонстрация включает в себя небольшое количество лесов для выполнения функции и форматирования вывода для отображения.

рассечение

Основной принцип состоит в том, что если остались n > 1игроки, один из них должен быть следующим, чтобы быть выбитым. Более того, порядок очереди после этого зависит только от начального порядка очереди и от того, кого выбьют. Таким образом, мы можем делать nрекурсивные вызовы, вычислять вероятности выигрыша для каждого игрока в каждом конкретном случае, а затем нам просто нужно соответствующим образом взвесить и добавить.

Я буду обозначать входные вероятности как [p_0 p_1 ... p_{n-1}]. Позвольте f(a,b)обозначить вероятность того, что aне в состоянии защитить от b. В любом раунде, вероятность того, что aзащищает успешно это p_a, вероятность того, что bстучит aаут (1-p_a)*p_b, и вероятность того, что он идет в другой раунд (1-p_a)*(1-p_b). Мы можем либо сделать явную сумму геометрической прогрессии, либо мы можем утверждать, что две геометрические прогрессии пропорциональны друг другу, чтобы рассуждать об этом f(a,b) = (1-p_a)*p_b / (p_a + (1-p_a)*p_b).

Затем мы можем повысить уровень до полного раунда линии. Вероятность поражения первого игрока равна f(0,1); вероятность того, что второй игрок выбит из игры, равна (1-f(0,1)) * f(1,2); третий игрок (1-f(0,1)) * (1-f(1,2)) * f(2,3); и т.д., пока последний не будет выбит с вероятностью \prod_i (1-f(i,i+1)) * f(n-1,0). Тот же аргумент о геометрических прогрессиях позволяет нам использовать эти вероятности в качестве весов с нормализацией с коэффициентом 1 / \prod_i f(i, i+1 mod n).

{                   e# Define a recursive function Q
  _,({              e# If we have more than one person left in the line...
    _,,{            e#   Map each i from 0 to n-1...
      _2$m<         e#     Rotate a copy of the probabilities left i times to get [p_i p_{i+1} ... p_{n-1} p_0 ... p_{i-1}]
      (;(+          e#     i fails to defend, leaving the line as [p_{i+2} ... p_{n-1} p_0 ... p_{i-1} p_{i+1}]
      Q             e#     Recursive call
      0\)\++        e#     Insert 0 for the probability of i winning and fix up the order
      m>\           e#     Rotate right i times and push under the list of probabilities
    }%
    )               e#   Stack: [probs if 0 knocked out, probs if 1 knocked out, ...] [p_0 p_1 ...]
    _(+.{           e#   Duplicate probs, rotate 1, and pointwise map block which calculates f(a,b)
      X2$-*_@+/     e#     f(a,b) = (1-p_a)*p_b / (p_a + (1-p_a)*p_b)  TODO is the d necessary?
    }
    1\{1$*\1$-}%    e#   Lift over the list of f(a,b) a cumulative product to get the weights  TODO is the d necessary?
    )1\-f/          e#   Normalise the weights
    .f*             e#   Pointwise map a multiplication of the probabilities for each case with the corresponding weight
    :.+             e#   Add the weights across the cases
  }{,da}?           e# ...else only one left, so return [1.0]
}:Q
Питер Тейлор
источник