如何使用计算方法(例如使用Python)找到以下期望概率?

How to find the following desired probability using computational method (e.g. using Python)?

我们 class 有 64 名学生。我们进行了一轮随机团队分配,很快就会进行第二轮。在每一轮中,我们将学生随机分成 16 组,每组 4 人。

第 1 轮没有一对队友在第 2 轮再次成为队友的概率是多少?

如果 "computationally" 你的意思是 "with a simulation":

import random

def make_teams(teamsize, numteams):
    students = list(range(teamsize * numteams))  # Py2 & Py3 compatible
    random.shuffle(students)
    teammates = {}
    for i in range(0, len(students), teamsize):
        team = set(students[i:i+teamsize])
        for t in team: teammates[t] = team.difference([t])
    return teammates

ref_tms = make_teams(4, 16)
common_teammates = 0
for i in range(10000):
    new_tms = make_teams(4, 16)
    if any(ref_tms[t].intersection(new_tms[t]) for t in ref_tms):
        common_teammates += 1
print('Common teammates seen in {} cases out of 10000'.format(
      common_teammates)

当然,10000 个示例的样本很小,但它应该开始给您一个想法。您可以 运行 这几次,看看频率(作为概率的估计值)如何变化,并计算置信区间等。

让我们根据第 1 轮的球队给学生贴上标签:

0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 AAAA BBBB CCCC DDDD EEEE FFFF

无限制分配第2轮球队的方式是

64! / ((4! ** 16) * (4! ** 16)) == 864285371844932000669608560277139342915848604
 ^        ^            ^
 |        |        ways of rearranging each round-2 team
 |     indistinguishable arrangements for round-1 team members
raw number of permutations

分配第 2 轮球队的方式数量 没有 每个球队的重复是复杂的,因为我们如何分配第一支球队改变了第二支球队可用的组合(等等在)。但它应该仍然可以通过巧妙的数学运算和仔细的记忆来处理!

from functools import lru_cache

# lookup table for `choose(n, k)` for n up to 16 and k up to 4
ncr = {}
for n in range(17):
    nn   = n
    ntok = 1
    ktok = 1
    ncr[n, 0] = 1
    for k in range(1, min(n, 4) + 1):
        ntok *= nn
        nn -= 1
        ktok *= k
        ncr[n, k] = ntok // ktok

@lru_cache(maxsize=None)
def team_combos(zeros, ones, twos, threes, fours):
    """
    Calculate the number of unique second-round 4-person
      team combinations such that no team has members from
      the same first-round team.
    """
    if ones or twos or threes or fours:
        total_ways = 0
        # number of members to take from teams having one person remaining
        for b in range(min(ones, 4) + 1):
            zeros_ = zeros + b
            b_ways = ncr[ones, b]
            b_rem = 4 - b   # number of members yet to be chosen
            # number of members to take from teams having two persons remaining
            for c in range(min(twos, b_rem) + 1):
                ones_ = ones - b + c
                bc_ways = b_ways * ncr[twos, c]
                bc_rem = b_rem - c  # number of members yet to be chosen
                # number of members to take from teams having three persons remaining
                for d in range(min(threes, bc_rem) + 1):
                    e = bc_rem - d  # number of members yet to be chosen
                    # ... all of which _must_ now come from
                    #   teams having four persons remaining
                    if e <= fours:
                        bcde_ways = bc_ways * ncr[threes, d] * ncr[fours, e]
                        total_ways += bcde_ways * team_combos(zeros_, ones_, twos - c + d, threes - d + e, fours - e)
        return total_ways
    else:
        return 1

然后

>>> team_combos(0, 0, 0, 0, 16)   # start with 16 four-person teams
6892692735539278753058456514221737762215000

那么最后的概率就是正好

>>> 6892692735539278753058456514221737762215000 / 864285371844932000669608560277139342915848604
0.0079750195480295