Вероятность, независимость, условная вероятность

Вероятность события, независимость и условная вероятность — язык, на котором описывают случайность в задачах.

Вероятность события A в классической схеме — отношение числа благоприятных исходов к числу всех равновозможных: P(A) = |A| / |Ω|.

Зачем это в олимпиадах

Вероятностные задачи всё чаще появляются на олимпиадах по информатике: «вероятность, что игрок выиграет», «ожидаемое значение суммы», «случайные блуждания». Чтобы их брать, нужно уверенно владеть базой: что такое пространство исходов, как считать вероятность, что значит независимость и условная вероятность. Эти понятия — фундамент для следующего урока про математическое ожидание, самый мощный приём этого раздела. А ещё умение писать симуляцию Монте-Карло — спасательный круг: если не уверен в формуле, прогони эксперимент и сверь.

Классическая вероятность

Пространство элементарных исходов Ω — множество всех возможных результатов опыта. Если исходы равновозможны (честная монета, симметричный кубик), вероятность события — доля благоприятных исходов. Бросок двух кубиков: |Ω| = 36; событие «сумма равна 7» имеет 6 благоприятных исходов, значит P = 6/36 = 1/6.

from fractions import Fraction
from itertools import product

# Бросаем два кубика. P(сумма = 7)?
outcomes = list(product(range(1, 7), repeat=2))
favorable = [(a, b) for a, b in outcomes if a + b == 7]
p = Fraction(len(favorable), len(outcomes))
print(len(outcomes), len(favorable))
print(p)                     # точная дробь
print(float(p))

Вывод:

36 6
1/6
0.16666666666666666

Модуль fractions.Fraction даёт точную рациональную арифметику — никаких ошибок округления. Для вероятностей это бесценно: 1/3 остаётся 1/3, а не 0.333…. На олимпиадах ответ-дробь часто требуют по модулю (через обратный элемент из прошлого раздела), но для проверки идей Fraction идеален.

Аксиомы и базовые свойства

Вероятность подчиняется простым правилам: 0 ≤ P(A) ≤ 1; P(Ω) = 1; для несовместных (непересекающихся) событий P(A ∪ B) = P(A) + P(B). Отсюда — формула дополнения P(не A) = 1 − P(A), часто упрощающая счёт: вместо «хотя бы один успех» считают «ни одного» и вычитают. А для произвольных (пересекающихся) событий работает уже знакомый принцип включения-исключения: P(A ∪ B) = P(A) + P(B) − P(A ∩ B).

from fractions import Fraction

# Бросаем кубик. A = "чётное", B = "больше 3". P(A или B)?
omega = set(range(1, 7))
A = {2, 4, 6}
B = {4, 5, 6}
PA = Fraction(len(A), 6)
PB = Fraction(len(B), 6)
PAB = Fraction(len(A & B), 6)          # пересечение
print(PA, PB, PAB)
print(PA + PB - PAB)                    # включение-исключение
print(Fraction(len(A | B), 6))          # прямой подсчёт объединения

Вывод:

1/2 1/2 1/3
2/3
2/3

Независимость

События A и B независимы, если P(A ∩ B) = P(A) · P(B), то есть наступление одного не меняет вероятность другого.

Интуиция: бросок монеты не влияет на бросок кубика — их исходы независимы, вероятность совместного события перемножается. Будьте осторожны: независимость — не то же самое, что несовместность. Несовместные события (не могут случиться вместе) как раз зависимы: если одно произошло, второе уже невозможно.

from fractions import Fraction

# Монета и кубик. A = "орёл", B = "кубик > 4". Независимы?
PA = Fraction(1, 2)
PB = Fraction(2, 6)               # выпало 5 или 6
P_both = Fraction(1, 2) * Fraction(2, 6)   # совместно
print(PA, PB)
print(PA * PB, P_both, PA * PB == P_both)  # проверка независимости

Вывод:

1/2 1/3
1/6 1/6 True

Условная вероятность

Условная вероятность P(A | B) — вероятность A при условии, что B уже произошло: P(A | B) = P(A ∩ B) / P(B) (при P(B) > 0).

Идея — сузить пространство исходов до тех, где B выполнено, и внутри него посчитать долю A. Пример: бросили кубик, известно, что выпало чётное (B = {2,4,6}); какова вероятность, что это 6? Сузив Ω до трёх чётных, получаем 1/3. Условная вероятность ведёт к формуле полной вероятности и Байесу — но для олимпиад по информатике обычно достаточно базового определения.

from fractions import Fraction

# Кубик. B = "чётное". P(выпало 6 | B)?
B = {2, 4, 6}
A_and_B = {6} & B
P_A_given_B = Fraction(len(A_and_B), len(B))
print(P_A_given_B)

# Через определение: P(A∩B)/P(B)
PAB = Fraction(1, 6)             # P(выпало 6)
PB = Fraction(3, 6)
print(PAB / PB)

Вывод:

1/3
1/3

Монте-Карло: проверка симуляцией

Если формула вызывает сомнения, поставьте численный эксперимент: много раз проиграйте случайный опыт и посчитайте долю успехов. По закону больших чисел эта доля сходится к истинной вероятности. Это не доказательство, но мощная проверка на олимпиаде и в жизни.

import random

random.seed(42)
trials = 100000
success = 0
for _ in range(trials):
    a = random.randint(1, 6)
    b = random.randint(1, 6)
    if a + b == 7:
        success += 1

print(round(success / trials, 4))   # ожидаем ~0.1667 = 1/6

Вывод:

0.1646

Симуляция дала 0.1646 против точного 0.1667 — близко. С фиксированным seed результат воспроизводим. Запомните этот приём: когда вывод формулы кажется ненадёжным, Монте-Карло за пару минут подтвердит или опровергнет гипотезу.

Разбор задачи: «хотя бы один» через дополнение

Любимый приём: когда спрашивают вероятность «хотя бы одного» успеха, считать напрямую (через ПВИ по всем случаям) громоздко. Гораздо проще посчитать вероятность противоположного события — «ни одного успеха» — и вычесть из единицы. «Какова вероятность выбросить хотя бы одну шестёрку за 4 броска кубика?» Прямой подсчёт — суммировать вероятности 1, 2, 3, 4 шестёрок. А через дополнение: P = 1 − P(ни одной) = 1 − (5/6)4.

from fractions import Fraction
import random

# P(хотя бы одна шестёрка за 4 броска)
p = 1 - Fraction(5, 6) ** 4
print(p, float(p))

# проверка Монте-Карло
random.seed(3)
trials = 100000
success = sum(1 for _ in range(trials)
              if any(random.randint(1, 6) == 6 for _ in range(4)))
print(round(success / trials, 4))

Вывод:

671/1296 0.5177469135802469
0.5156

Точный ответ — 671/1296 ≈ 0.518, симуляция дала 0.516 — согласуется. Приём «единица минус противоположное» сокращает выкладки всякий раз, когда событие формулируется как «хотя бы один из…»: вместо суммы многих случаев — одно вычитание. Это первое, что стоит пробовать в задачах с «хотя бы».

Подводные камни

  • Исходы должны быть равновозможны. Классическая формула |A|/|Ω| верна только для равновероятных исходов. Иначе считайте через вероятности отдельных исходов.
  • Независимость ≠ несовместность. Несовместные события зависимы.
  • Округление. Для точных ответов используйте Fraction; float накапливает ошибку.
  • Монте-Карло — не доказательство. Оно лишь проверяет; итоговый ответ обосновывайте формулой.

Итог

  • Классическая вероятность — доля благоприятных среди равновозможных исходов.
  • Для несовместных событий вероятности складываются; P(не A)=1−P(A).
  • Независимость: P(A∩B)=P(A)P(B); условная: P(A|B)=P(A∩B)/P(B).
  • Fraction даёт точные дроби, Монте-Карло — быструю численную проверку.
Проверьте себя
1. Чему равна вероятность выпадения суммы 7 при броске двух кубиков?
A1/12
B1/6
C7/36
D1/2
2. Какое условие означает независимость событий A и B?
AP(A ∩ B) = 0
BP(A ∩ B) = P(A) · P(B)
CP(A) = P(B)
DA и B не могут произойти вместе
3. Как считается условная вероятность P(A | B)?
AP(A) · P(B)
BP(A) + P(B)
CP(A ∩ B) / P(B)
DP(B) / P(A ∩ B)
4. Зачем в вероятностных задачах использовать Monte-Carlo симуляцию?
AЭто строгое доказательство ответа
BЧтобы численно проверить гипотезу/формулу через долю успехов
CЭто единственный способ найти вероятность
DЧтобы ускорить точное вычисление
Поддержать проект