组合数的计算(3种方法)
## 组合数的计算
##1、定义
def Cnm(n,m):
ans=1
for i in range(1,n+1):
ans*=i
for i in range(1,m+1):
ans//=i
for i in range(1,(n-m)+1):
ans//=i
return ans
##2、递推公式
## Cnm=Cn-1m-1+Cn-1m
## 该方法完全不涉及阶乘计算
## 但是会产生重复计算的问题
## 递归
def Cnm_2(n,m):
if m==0 or m==n:
return 1
return Cnm_2(n-1,m)+Cnm_2(n-1,m-1)
##2、递推公式(把整张表计算出来)
## 递推
def calC(n,m):
res=[[0]*(1+n) for _ in range(1+n)]
## 边界条件初始化
for i in range(1+n):
res[i][0]=res[i][i]=1
for i in range(2,1+n):
for j in range(1,i//2+1):
res[i][j]=res[i-1][j-1]+res[i-1][j]
res[i][i-j]=res[i][j]
return res
##3、公式变形
def calC_2(n,m):
ans=1
for i in range(1,m+1):
ans=ans*(n-m+i)//i
return ans
print(Cnm(4,2))
print(Cnm_2(4,2))
res=calC(4,4)
print(res[4][2])
print(calC_2(4,2))
Cnm%p的计算(4种方法)
##Cnm%p的计算
## 法一、通过递推公式计算
## 递归
def calC_1(n,m,p):
if m==0 or m==n:
return 1
return (calC_1(n-1,m-1,p)+calC_1(n-1,m,p))%p
## 递推
def calC_2(n,m,p):
res=[[0]*(1+n) for _ in range(1+n)]
## 初始化
for i in range(1+n):
res[i][0]=res[i][i]=1
for i in range(2,1+n):
for j in range(i//2+1):
res[i][j]=(res[i-1][j-1]+res[i-1][j])%p
res[i][i-j]=res[i][j]
return res
##法二、根据定义计算
## 运用到N!的一个问题中cal函数
##法三、定义变形
##法四、Lucas定理
def C(n,m):
if m==0 or m==n:
return 1
return C(n-1,m-1)+C(n-1,m)
p=5
def Lucas(n,m):
global p
if m==0:
return 1
return C(n%p,m%p)*Lucas(n//p,m//p)%p
print(calC_1(4,2,5))
res=calC_2(4,4,5)
print(res[4][2])
print(Lucas(4,2))