排列组合——n个人平均分成m组

  本文介绍了排列组合经典问题——n个人平均分成m组的解法(公式),并给出其Python程序,详情如下。


1 解法公式

  求n个人平均分成m组的分配法。设分配方法共 N N N种,每组 k = n m k=\frac{n}{m} k=mn人,则:
N = { 0 , n < m  or  n % m ≠ 0 1 , n = m C n k C n − k k C n − 2 k k ⋯ C 2 k k C k k A m m , n > m  and  n % m = 0 N = \begin{cases} 0, & \text{$n<m$ or $n \%m \neq 0$} \\[2ex] 1, & \text{$n=m$} \\[2ex] \frac{C_n^k C_{n-k}^k C_{n-2k}^k \cdots C_{2k}^k C_k^k}{A_m^m}, & \text{$n>m$ and $n \%m=0$} \end{cases} N=0,1,AmmCnkCnkkCn2kkC2kkCkk,n<m or n%m=0n=mn>m and n%m=0式中,除以 A m m A_m^m Amm是为去重

2 Python程序

  Python程序如下:

'''
Author: xyyang
date: 2022-11-11
qq: 1391650991
'''
from scipy.special import comb,perm#组合、排列

def PC_n2m(n,m):
    if n<0 or m<0 or (not isinstance(n,int)) or (not isinstance(m,int)):
        print("人数或分组数据有误!")
        return
    if n<m or n%m!=0:
        return 0
    if n==m: #n%m=0
        return 1
    if n>m and n%m==0:
        k=n//m
        N=1
        for i in range(m):
            N*=comb(n-i*k,k)
        N=N/perm(m,m) #去重
        return N
    
if __name__=='__main__':
    n=6;m=3
    print("{0}人平均分成{1}组,共{2}种方法".format(n,m,PC_n2m(n,m))) #15
    #print(f"{n}人平均分成{m}组,共{PC_n2m(n,m)}种方法")

或者

'''
Author: xyyang
date: 2022-11-11
qq: 1391650991
'''
from scipy.special import comb,perm#组合、排列

def PC_n2m(n,m):
    if n<0 or m<0 or (not isinstance(n,int)) or (not isinstance(m,int)):
        print("人数或分组数据有误!")
        return
    if n%m!=0:
        return 0
    else:
        if n==m:
            return 1
        else:
            k=n//m
            N=1
            for i in range(m):
                N*=comb(n-i*k,k)
            N=N/perm(m,m) #去重
            return N

if __name__=='__main__':
    n=6;m=3
    print("{0}人平均分成{1}组,共{2}种方法".format(n,m,PC_n2m(n,m))) #15
    #print(f"{n}人平均分成{m}组,共{PC_n2m(n,m)}种方法")
### C++归并排序算法时间复杂度分析 #### 时间复杂度概述 归并排序的核心思想是分治法,即将待排序的数分为两部分分别进行排序,然后再将这两部分合并为一个有序的整体。这种递归的过程决定了其时间复杂度主要由两个因素决定:划分阶段和合并阶段。 每次划分都将当前区间分两半,直到每个子区间的长度为1为止。这一过程总共会执行$log_2 n$次分割[^3]。而在每一轮分割之后,都需要对左右两部分的结果进行合并操作,这个合并操作的时间复杂度为O(n),其中$n$表示当前层所有元素的数量总和[^2]。 因此,在最坏情况下、平均情况以及最好情况下,归并排序的时间复杂度均为O(n log n)[^3]。这是因为无论输入数据如何分布,归并排序始终按照固定的模式完所有的比较与移动工作。 #### 代码示例及其复杂度解释 以下是基于C++实现的一个标准版本的归并排序: ```cpp void merge(int arr[], int l, int m, int r) { int i, j, k; int n1 = m - l + 1; // 左边区域大小 int n2 = r - m; // 右边区域大小 /* 创建临时数 */ int L[n1], R[n2]; /* 将数据复制到临时数里 */ for (i = 0; i < n1; i++) L[i] = arr[l + i]; for (j = 0; j < n2; j++) R[j] = arr[m + 1 + j]; /* 合并临时数回到原数arr[l..r]*/ i = 0; // 初始化第一个索引 j = 0; // 初始化第二个索引 k = l; // 初始合并位置 while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k++] = L[i++]; } else { arr[k++] = R[j++]; } } /* 复制剩余元素 */ while (i < n1) arr[k++] = L[i++]; while (j < n2) arr[k++] = R[j++]; } /* 主函数用于调用merge()来完整个数的排序 */ void mergeSort(int arr[], int l, int r) { if (l >= r){ return;// 返回条件 } int m = l + (r-l)/2; mergeSort(arr,l,m); // 对左半部分进行递归排序 mergeSort(arr,m+1,r); // 对右半部分进行递归排序 merge(arr,l,m,r); // 合并已排序的部分 } ``` 上述`merge()`方法负责把两个已经排好序的小序列一个新的大序列;而`mergeSort()`则不断拆解原始的大问题直至不可再分解的程度——即当$l \geq r$时停止进一步细分,并开始回溯过程中逐步构建最终解决方案。这里的关键在于理解每次递归都会减少一半的数据量处理规模的同时引入了一个线性的额外开销用来重这些被分开处理过的片段。 #### 总结 综上所述,由于归并排序采用了递归方式将初始列表逐级划分为更小单元后再逐一整合起来形整体顺序排列结果的特点,所以它具备稳定性和较高的效率表现,具体表现为总体运行时间为Θ(n log n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C_xxy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值