从排列与组合的python实现到"生日问题"的解释

161 篇文章 8 订阅
14 篇文章 31 订阅

数论及Python实践一文中,我们介绍了组合的基本定义以及一些常规实现方法,并未充分发挥python语言的优势,本文我们从reduce函数的角度(从这个角度我们应当恢复reduce正宫娘娘的地位,因为在python3中Guido将reduce从系统内置函数降格为functools中的函数),重新实现给出排列组合的各自实现,以及据此给出”生日问题”的概率解释。

 (nk)=n!k!(nk)! (nk)=(n1k)+(n1k1)  

第二行公式可看做其递归定义式。我们换个记号继续推导:
C k n === C k n1 +C k1 n1 C k n1 +C k1 n2 +C k2 n2   

这里还有一个经典的结论:
 k=0 n (nk)=2 n  

如何证明,其实很简单,回归定义(组合数combination,又叫二项式系数binomial coefficients),对 2 n   进行二项展开,即:
2 n === (1+1) n (n0)+(n1)++(nn1)+(nn) k=0 n (nk)  

2 n   这不正是二进制嘛!这个结论有什么用?举个栗子,给定三个卡片,编号为 13  ,使用该等式可得其会有 2 3 =8  种组合(combinations或叫subsets)(包括空集):

|{{};{1};{2};{3};{1,2};{1,3};{2,3};{1,2,3}}|=8 

以二进制的形式理解的话即为:

  • 0:000
  • 1:001
  • 2:010
  • 3:011
  • 4:100
  • 5:101
  • 6:110
  • 7:111

再来考虑这样一种情形,从 n  个数中随机选择 k 个,再从余下的 nk  个随机选择 p  个,组合数一共多少:

(nk)(nkp)=n!k!(nk)! (nk)!p!(nkp)! =n!k!p!(nkp)!  

将此记为: (nk,p)  ,也即 (nk,p)=n!k!p!(nkp)!  

再来看几个结论:

A k n =n!(nk)!  

所以有:
(nk)A k k =n!k!(nk)! k!=A k n  

N k [A k N =(Nk)A k k ] 

左边允许重复,右边不允许重复;

当我们试图用reduce实现组合数的计算时,

(nk)=n!k!(nk)! = i=nk+1 n ik! =A k n k!  

from functools import reduce
import operator

def fac(n):
    return reduce(operator.mul, range(1, n+1), 1)
                            # 阶乘n!的定义
                            # reduce与operator.mul结合
def perm(n, k):
    return reduce(operator.mul, range(n-k+1, n+1), 1)   
                            # 排列数的定义
def comb(n, k):
    return perm(n, k)//fac(k)                   

def test():
    print('{}!={}'.format(5, fac(5)))
    print('A_{}^{}={}'.format(5, 2, perm(5, 2)))
    print('C_{}^{}={}'.format(5, 2, comb(5, 2)))
if __name__ == '__main__':
    test()

运行结果为:

5!=120
A_5^2=20
C_5^2=10

由以上准备,我们可求解概率论史上的经典问题(概率论史上的经典问题一般是指违反直觉的那些问题)”生日问题”:

一次聚会上,只要有23个人,就有50%的可能性其中至少有两个人生日相同,如果人数达到50人,至少有两个人生日相同的概率达到97%。(这个结论很恐怖,只要是班上的人数超过50,老师便可以说,我们班至少有两个人生日相同,其实在人数超过23的时候,我们便可以这么说,应为概率占优,注意,是班上会有来个人生日相同,不是说,班上至少存在一个人生日生日与相同)。

当然这类问题从其反问题对立事件出发, 1P()=P() 

p=1A 23 365 365 23  p=1A 50 365 365 50   

这里的 A 50 365   可以理解为,随意指定一个生日,他生日所在的自由度(或者作可选空间)为365,则下一个人只有365-1的自由度,依次类推。 365 50   是考虑到这50个人的生日大体独立,也即每一个的生日都有365个自由度(也即365种选择)。所谓概率,频率的观点(另有贝叶斯的观点)来看就是出现的次数与总的可能性之比。

>>> 1-perm(365, 23)/(365**23)
0.5072972343239854
>>> 1-perm(365, 50)/(365**50)   
0.9703735795779884

注意:如果预先指定一个生日,随机选取125人,250人,500人,出现某人生日正好是这一生日的概率分别是:

1(364365 ) 125 0.290316187907482261(364365 ) 250 0.496348886853832051(364365 ) 500 0.7463355562266258 

比想象的要小很多,再次说明概率中的许多问题都比较违反直觉。

补充:

365 50 (36550)A 50 50  

为什么不等于呢?在于,左边 允许重复(同一个位置,既可以是你,也可以是他),右边 不允许重复

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值