Вашият рожден ден има 23 гости. Двама от тях вероятно споделят рожден ден. Но изчакайте, има странен обрат, при който може да се наложи да пуснете средно 25!

Колко души трябва да са средно на парти, така че поне двама от тях да споделят рожден ден? Това е вид проблем, с който Python блести, когато се справите с него със симулация на Монте Карло. Разбира се, можете да намерите формула за вероятност (погледнете в Уикипедия, за да я намерите), но симулирането на ситуацията може да бъде забавно и поучително.

Но дръжте шапката си за парти!

Когато програмирах това, открих много странен резултат, който все още се опитвам да обмисля. Нека обясня.

Първо, ето кратка програма на Python, която е съгласна с всички експерти и има смисъл.

import random
parties = 10000
hits = 0
days = list(range(365))
for i in range(parties):
    guest_birthdays = random.choices(days, k=23)
    if len(set(guest_birthdays)) < 23:
        hits += 1
print(hits / parties)

Променливата days е списък с цели числа от 0 до 364, всяко от които представлява един ден от типична 365-дневна година. За всяка страна произволно се избира набор от 23 дни от списъка с дни, за да се създаде списък от 23 guest_birthdays. Функцията choices() използва „със замяна“, което означава, че избраните дни евентуално могат да се повторят в списъка, който се връща.

Чрез преобразуването на този списък от 23 рождени дни на гости в set, всички повторения се премахват, което прави броя на набора по-малък от 23, ако всеки двама гости споделят рожден ден. Изчислява се частта от случаите, в които това се случва по време на всичките 10 000 партита, и средно се равнява на малко повече от половината време. Това само по себе си е доста невероятно.

Сега става странно

Вместо да пускаме 23-ма души на вратата и след това да сравняваме рождените дни, нека пускаме купонджиите един по един.

Когато всеки гост пристигне, ние добавяме неговия номер на рожден ден към списък, като проверяваме дали съвпада с някой от рождените дни на госта, които вече са в списъка.

Веднага след като намерим съвпадение, спираме да пускаме повече гости и пресмятаме колко са необходими, за да получим двама гости с еднакъв рожден ден.

След десет хиляди партита бихте си помислили, че средният брой гости за намиране на съвпадение трябва да е по-малко от 23. В крайна сметка, както е показано по-горе, при 23 гости шансовете са по-големи от 50-50, че има съвпадение.

Но се оказва, че трябва да пуснете средно по 25 гости, преди да намерите двама гости с общи рождени дни!

Ето кратка програма на Python, която демонстрира това действие.

import random
parties = 10000
total_guests = 0
for i in range(parties):
    guest_birthdays = []
    while True:
        bd = random.randrange(365)
        guest_birthdays.append(bd)
        if bd in guest_birthdays[:-1]:
            break
    party_guests = len(guest_birthdays)
    total_guests += party_guests
print(total_guests / parties)

За всяко от 10 000-те партита допускаме гости (добавяме номера на рождения им ден към списъка), докато накрая имаме двама гости със съвпадащи рождени дни. Забележете, че проверяваме току-що добавения рожден ден, за да видим дали съществува някъде по-рано в списъка, използвайки този код… if bd in guest_birthdays[:-1]:

Броят на гостите, допуснати до вратата на всяко парти, се изчислява и се използва за изчисляване на средния брой гости на парти, преди да бъдат намерени съвпадащи рождени дни.

Напълно очаквах средният брой гости да бъде малко под 23, въз основа на стандартния пъзел. Но броят на гостите винаги е средно около 24,6, което означава, че са необходими средно 25 гости един по един, за да се гарантира, че има съвпадение през половината от времето. Странно.

Все още търсите обяснение!

Всеки път, когато се сблъскам с предизвикателства като това, имам склонност да довеждам ситуацията до нейните крайности, за да видя дали това опростява логиката.

В този случай, вместо 365 възможни рождени дни, настройвам кода за двоична ситуация. Ако посетителите на партито са случайно мъже или жени, колко трябва да пуснете на вратата, за да получите двама от един и същи пол? Погледнато от друга страна, ако има двама души на парти, какви са шансовете те да са от един и същи пол?

Съвет: отговорите не са еднакви!

Достатъчно скромен съм, за да призная, че все още нямам ясно обяснение за разликата между двете програми по-горе и приветствам всички предстоящи обяснения, които, надявам се, са ясни и кратки. Имате ли?

Want to Connect?
John is the author of Python for Numworks , Python for OpenSCAD, Python for the TI-Nspire CX II, Python for the TI-84 Plus CE Python calculator, Python for CASIO Calculators, and many other titles.