对双胞胎团聚的概率进行编程

Programming a probability of twins reunion

我有如下问题,我试过了,但找不到正确的结果。我想在不使用额外库的情况下以简单的方式解决它。我没有任何数据可以分享,因为我无法建立正确的逻辑。

4 对双胞胎(总共 8 children)闭着眼睛玩耍。关键时刻到来时,随机分配的 children 组中的 children 成对握住彼此的手。如何写一个python脚本,列出所有的可能性,并标出兄弟姐妹牵手的概率?

list = ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2']

我想得到这样的结果:

[a1a2, b1b2, c1c2, d1d2] - Found
[a1a2, b1b2, c1d1, c2d2] - Not found
[a1a2, b1b2, c1d2, c2d1] - Not found
[a1a2, b1b2, c1d1, c2d2] - Not found
[a1a2, b2b1, c1d1, c2d2] - Not found
...
all possible matches
...

感谢您的帮助。

如果包含的库适合您,您可以尝试使用 random.choice()。

我还添加了一小部分,估计找到正确双胞胎的概率。

尝试以下操作:


    import random
    
    twins= ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2']
    twinsToFind= ['a1','a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2']
    
    # Loop over the list
    for i in range(0, 4):
    
        searcher = twins[0]
    
        # remove the searching twin, since he shouldn't find "himself"
        twinsToFind.remove(searcher)
        # also remove him from the list, since he won't search again
        twins.remove(searcher)
    
        # variable for the probability of finding the right twin
        prob = 0
    
        # loop over to second list to check how possible it is to find the right twin
    
        for y in twinsToFind:
            if searcher[0] == y[0]:
                prob =+1
    
        # estimating the probability
    
        prob = prob/len(twinsToFind)
    
        # printing the probability
        # casting it to inc gets rid of the digits behind the comma
        # multiplying it with 100 gives the probability in percent
    
        print("The probability to find the right twin is: "+str(int(prob*100))+"%")
    
        # find a random twin
    
        found = random.choice(twinsToFind)
    
        # print a message if it's the right twin
    
        if searcher[0] == found[0]:
            print("==> Right twin found: "+searcher+found)
    
        # remove the "found" twin from the list, because he won't search again
    
        twins.remove(found)
    
        # remove the found twin from the second list, because he shouldn't be found again 
        # (yeah, sounds a bit dark, but you get it, I guess)
    
         twinsToFind.remove(found)
         print("Found:"+searcher+"<->"+found)

创建所有配对并与正确的配对进行比较

首先,定义一个生成所有配对的函数,以及一个生成正确配对的函数:

def all_pairings(l):
  if len(l) == 0:
    return [[]]
  else:
    return [[(l[0],l[i])] + p for i in range(1,len(l)) for p in all_pairings(l[1:i]+l[i+1:])]

def adjacent_pairing(l):
    it = iter(l)
    return zip(it, it)

那就是for-loop:


children = ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2']

correct_pairing = set(adjacent_pairing(children))

for pairing in all_pairings(children):
    sentence = 'Found' if set(pairing) == correct_pairing else 'Not found'
    print(', '.join(''.join(pair) for pair in pairing), ' -- ', sentence)

输出:

a1a2, b1b2, c1c2, d1d2  --  Found
a1a2, b1b2, c1d1, c2d2  --  Not found
a1a2, b1b2, c1d2, c2d1  --  Not found
a1a2, b1c1, b2c2, d1d2  --  Not found
...
a1d2, a2d1, b1b2, c1c2  --  Not found
a1d2, a2d1, b1c1, b2c2  --  Not found
a1d2, a2d1, b1c2, b2c1  --  Not found

洗牌配对

我建议在迭代之前使用random.shuffle打乱可能的配对(否则,正确的配对总是第一个生成的配对,这有点无聊)。

import random

l = list(all_pairings(children))
random.shuffle(l)
for pairing in l:
    sentence = 'Found' if set(pairing) == correct_pairing else 'Not found'
    print(', '.join(''.join(pair) for pair in pairing), ' -- ', sentence)

输出:

a1a2, b1d2, b2d1, c1c2  --  Not found
a1d1, a2d2, b1c2, b2c1  --  Not found
a1b2, a2c2, b1c1, d1d2  --  Not found
...
a1b1, a2c2, b2d1, c1d2  --  Not found
a1a2, b1b2, c1c2, d1d2  --  Found
a1b2, a2c2, b1d2, c1d1  --  Not found
...
a1c2, a2d2, b1b2, c1d1  --  Not found
a1c2, a2d2, b1c1, b2d1  --  Not found
a1b1, a2b2, c1c2, d1d2  --  Not found

找到正确配对的概率

假设所有配对都是等概率的,随机选择一对时找到正确配对的概率是 1 除以不同可能配对的总数。

有多少种不同的可能配对?

选择有序配对,其中配对的顺序很重要,每对中两个 children 的顺序很重要,与选择排列相同。众所周知,Nchildren.

N!种可能的排列

每个无序对对应多少个有序对?

每对 2 children 有 2 种可能的订购方式;因此有 2 ** (N / 2) 种方法来订购所有对中的 2 children。

(N / 2)! 种可能的方式来订购 N / 2 对。

因此,每个配对对应 (N / 2)! * 2 ** (N / 2) 个有序配对。

因此,N children.

必须有 N! / ( (N / 2)! * 2 ** (N / 2) ) 个不同的可能配对

你的 8 children,就是 8! / (4! * 2**4) == 105

在所有不同的可能配对中均匀随机选择时,选择正确配对的概率是该数字的 1:

在8 children.

的情况下略低于1%

随机配对中预期的正确对数

让我们在所有不同的可能配对中随机选择一个配对。该配对中平均有多少对是正确的?

我们可以在我们的 python 程序中计算每个配对中的正确对数:

for pairing in all_pairings(children):
    nb_correct_pairs = len(set(pairing) & correct_pairing)
    print(', '.join(''.join(pair) for pair in pairing), ' -- ', nb_correct_pairs)

输出:

a1a2, b1b2, c1c2, d1d2  --  4
a1a2, b1b2, c1d1, c2d2  --  2
a1a2, b1b2, c1d2, c2d1  --  2
a1a2, b1c1, b2c2, d1d2  --  2
a1a2, b1c1, b2d1, c2d2  --  1
a1a2, b1c1, b2d2, c2d1  --  1
a1a2, b1c2, b2c1, d1d2  --  2
a1a2, b1c2, b2d1, c1d2  --  1
...
a1d2, a2c1, b1d1, b2c2  --  0
a1d2, a2c2, b1b2, c1d1  --  1
a1d2, a2c2, b1c1, b2d1  --  0
a1d2, a2c2, b1d1, b2c1  --  0
a1d2, a2d1, b1b2, c1c2  --  2
a1d2, a2d1, b1c1, b2c2  --  0
a1d2, a2d1, b1c2, b2c1  --  0

平均数其实用数学很容易算出来

让我们考虑随机配对中的一个特定 child,例如 child a1。 child a1 握住双胞胎手的概率是多少?由于还有 N-1 个其他 children,并且根据对称性,所有 children 的可能性均等,因此 child a1 将握住双胞胎手的概率是 1/(N-1).

当然,这适用于所有child人,而不仅仅是a1。因此,平均而言,child 人中的 1/(N-1) 人会握住自己双胞胎的手。既然有Nchildren,那么平均来说,N/(N-1) == 1 + 1/(N-1)children会牵起自己双胞胎的手。由于每对有 2 children,这意味着在随机配对中平均会有 N / (2(N-1)) == (1 + 1/(N-1)) / 2 个正确的对。

N == 8 的情况下,这意味着每个配对 4/7 ≈ 0.571 对。

让我们通过实验验证一下:

l = list(all_pairings(children))
total_correct_pairs = sum(len(set(pairing) & correct_pairing) for pairing in l)
n_pairings = len(l)
expected_correct_pairs = total_correct_pairs / n_pairings
print('Expected number of correct pairs: ', expected_correct_pairs)

输出:

Expected number of correct pairs:  0.5714285714285714