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

 (nk)=n!k!(n−k)! (nk)=(n−1k)+(n−1k−1)  

\begin{split} &\binom{n}{k}=\frac{n!}{k!(n-k)!}\\ &\binom{n}{k}=\binom{n-1}{k}+\binom{n-1}{k-1} \end{split}
第二行公式可看做其递归定义式。我们换个记号继续推导:

C k n === C k n−1 +C k−1 n−1 C k n−1 +C k−1 n−2 +C k−2 n−2 ⋯  

\begin{split} C_n^k=&C_{n-1}^k+C_{n-1}^{k-1}\\ =&C_{n-1}^k+C_{n-2}^{k-1}+C_{n-2}^{k-2}\\ =&\cdots \end{split}
这里还有一个经典的结论:

∑ k=0 n (nk)=2 n  

\sum_{k=0}^n\binom{n}{k}=2^n
如何证明,其实很简单,回归定义(组合数combination,又叫二项式系数binomial coefficients),对 2 n  2^n进行二项展开,即:

2 n === (1+1) n (n0)+(n1)+⋯+(nn−1)+(nn)∑ k=0 n (nk)  

\begin{split} 2^n=&(1+1)^n\\ =&\binom n0+\binom n1+\cdots+\binom n{n-1}+\binom n{n}\\ =&\sum_{k=0}^n\binom nk \end{split}

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

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

|\{\{\};\{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 n个数中随机选择 k k个,再从余下的 n−k n-k个随机选择p p个,组合数一共多少:

(nk)⋅(n−kp)=n!k!(n−k)! ⋅(n−k)!p!(n−k−p)! =n!k!p!(n−k−p)!  

\binom{n}{k}\cdot\binom{n-k}{p}=\frac{n!}{k!(n-k)!}\cdot\frac{(n-k)!}{p!(n-k-p)!}=\frac{n!}{k!p!(n-k-p)!}
将此记为:(nk,p) \binom{n}{k,\,p},也即 (nk,p)=n!k!p!(n−k−p)!  \binom{n}{k,\,p}=\frac{n!}{k!p!(n-k-p)!}

再来看几个结论:

A k n =n!(n−k)!  

A_n^k=\frac{n!}{(n-k)!}
所以有:

(nk)A k k =n!k!(n−k)! k!=A k n  

\binom{n}{k}A_k^k=\frac{n!}{k!(n-k)!}k!=A_n^k

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

N^k\neq \left [ A_N^k=\binom{N}{k}A_k^k\right ]

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

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

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

\binom{n}{k}=\frac{n!}{k!(n-k)!}=\frac{\prod\limits_{i=n-k+1}^ni}{k!}=\frac{A_n^k}{k!}

from functools import reduce
import operatordef 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的时候,我们便可以这么说,应为概率占优,注意,是班上会有来个人生日相同,不是说,班上至少存在一个人生日生日与相同)。

当然这类问题从其反问题对立事件出发,1−P(所有人都不在同一天)=P(至少有两人在同一天) 1-P(所有人都不在同一天)=P(至少有两人在同一天),

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

p=1-\frac{A_{365}^{23}}{365^{23}}\\ p=1-\frac{A_{365}^{50}}{365^{50}}

这里的A 50 365  A_{365}^{50}可以理解为,随意指定一个生日,他生日所在的自由度(或者作可选空间)为365,则下一个人只有365-1的自由度,依次类推。365 50  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 

1-(\frac{364}{365})^{125}\approx0.29031618790748226\\ 1-(\frac{364}{365})^{250}\approx0.49634888685383205\\ 1-(\frac{364}{365})^{500}\approx0.7463355562266258

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

补充:

365 50 ≠(36550)A 50 50  

365^{50} \neq \binom{365}{50}A_{50}^{50}
为什么不等于呢?在于,左边 “允许重复”(同一个位置,既可以是你,也可以是他),右边 不允许重复

从排列与组合的python实现到生日问题的解释相关推荐

  1. 笔记:《深入浅出统计学》第六章:排列与组合(Python实现)

    1.排列--选取对象并关注这些对象的排位顺序 一般排列:n! 圆形排列:(n-1)! 重复排列(k为重复对象数):n!/k! import itertools itertools.permutatio ...

  2. python中如何求列表中的和_python实现求解列表中元素的排列和组合

    求解列表中元素的排列和组合问题这个问题之前就遇到过几次没有太留意,最近在做题的时候遇上挺多的排列组合问题的,想来有必要温习一下了,今天花点时间写一下,之前都是手工写的,后来知道可以直接使用python ...

  3. Python | 排列与组合

    本文简要总结在 Python 中实现排列与组合的方法. Update: 2022 / 11 / 21 Python | 排列与组合 总览 方法 itertools 用法 示例 不考虑顺序 考虑顺序 n ...

  4. itertools库常用高效迭代器一览表,帮你快速实现数据的排列组合【python】

    itertools库常用高效迭代器一览表,帮你快速实现数据的排列组合 文档: https://docs.python.org/zh-cn/3/library/itertools.html iterto ...

  5. 算法第二期——排列组合(Python)

    目录 排列函数permutations( ) 易错点 组合函数combinations( ) 手写排列和组合代码 1.暴力法

  6. 数学基础知识-排列与组合

    文章目录 前言 一.分步乘法原理 1.定义 2.举例 二.排列 1.定义 2.计算公式 3.举例分析 4.公式推导过程 三.组合 1.定义 2.计算公式 3.举例分析 4.其他一些规定和转换 总结 前 ...

  7. Permutation test(排列(组合)检验)

    2019独角兽企业重金招聘Python工程师标准>>> 对Permutation test 的首次描述可追溯到上个世纪30年代, Fisher( 1935) 和Pitman( 193 ...

  8. 多重集合的排列和组合问题

    多重集合的排列和组合问题 标签: permutationn2c扩展 2012-04-17 16:18 5671人阅读 评论(0) 收藏 举报  分类: 算法(12)  版权声明:本文为博主原创文章,未 ...

  9. 排列与组合的一些定理(二)

    一,容斥原理 设S是一个集合,Ai 是S 中具有性质 Pi 的元素组成的子集合.那么,S中既不具有性质P1,也不具有性质P2,...更不具有性质Pn 的元素个数为: 二,容斥原理计算 有限制的重组合问 ...

最新文章

  1. java jfreechart 画图_java – Jfreechart XYPlot,我如何将绘图绘制到绘图区?
  2. How to Use Git
  3. python创建sqlite3数据库_Python之Sqlite3数据库基本操作
  4. TypeError: the JSON object must be str, bytes or bytearray, not NoneType
  5. how to find data source of F4 help in web client UI
  6. js进阶 13 jquery动画函数有哪些
  7. DelphiXE10.4安卓编程初学者心得
  8. SQL server中表数据自动生成拼音码
  9. 斯坦福NLP名课带学详解 | CS224n 第14讲 - Transformers自注意力与生成模型(NLP通关指南·完结)
  10. Win10系统电脑开机后显示无法登录到你的账户解决办法(亲测)
  11. 《唯有时间能证明伟大:极客之王特斯拉传》读后感
  12. np.random用法
  13. IOS小知识点5之内存警告、循环引用、交叉引用
  14. ROS中的imu_transformer包是什么,在哪里可以下载啊
  15. 计算机word文例试题及答案,大学计算机考试word试题及答案
  16. (线段树)洛谷 P2471 [SCOI2007]降雨量
  17. PDF转Word神器—ABBYY FineReader,这个必须有!(图文)
  18. PingCAP Clinic 服务:贯穿云上云下的 TiDB 集群诊断服务
  19. Linux-nginx配置文件详解与配置与请求行/头/体过长414、413配置
  20. netstat -anp 显示系统端口使用情况

热门文章

  1. 【Linux 命令学习第一天
  2. win7 更新android sdk,大神为你详解win7系统android sdk manager无法更新的处理对策
  3. python 使用迭代来创建集合
  4. 循环冗余校验 使用及记忆方法
  5. php在浏览器输入路径,关于在sublime text 3 中配置一键浏览器打开php文件,并且是在localhost 本地服务器路径下...
  6. C语言强制转换与输出格式不对应问题
  7. 对于有一定编程基础的学生来说,看下面这个链接的文章比较好
  8. 剑指offer面试题17. 打印从1到最大的n位数
  9. 最新生成树之克鲁斯卡尔算法
  10. 计算机核心期刊、学报一览