排列组合——排列公式的推理和组合

加法原理和乘法原理,是排列组合中的二条基本原理,在解决计数问题中经常运用。掌握这两条原理,并能正确区分他们,至关重要。

加法原理

若完成一件事情有3类方式,其中第一类方式有1种方法,第二类方式有3种方法,第三类有2种方法,这些方法都不相同,但任选一种方法都可以完成此事,则完成这件事情共有1+3+2=6种方法,这一原理称为加法原理。
例如:从甲地到乙地有三类方式,一是汽车,二是火车,三是飞机。若一天中汽车有2班,火车有4班,飞机有一班,那么从甲地到乙地共有多少种不同的走法。共有2+4+1=7种。

乘法原理

若完成一件事情分r个步骤,其中第一个步骤有m1种方法,第二个步骤有m2种方法……第步骤共有mr种方法,各步骤连续或同时完成,这件事才算完成,则完成这件事共有m1*m2*……*mr种方法。
例如:从甲地到丙地必须经过乙地。从甲地到乙地有4条路线,从乙地到丙地有3条路线,问从甲地到丙地共有多少种不同的走法?
解:要从甲地到达丙地,必须经过两个步骤:先从甲地到乙地,有4条路线;再从乙地到丙地,有3条路线。只有这两个步骤都完成了,才能完成这种事情,缺少哪一个步骤都不行。因此从甲地到丙地共有4*3=12种走法。

加法原理和乘法原理的区别

以上两个基本原理在排列组合问题中将会反复使用。这两个原理回答的都是关于完成一件事情的不同方法的种数问题,但是又有根本区别。加法原理针对的是“分类”问题,若完成一件事情有多类方式,每一类方式的各种方法相互独立,用其中任何一种方法都可以完成这件事情,则用加法原理;而乘法原理针对的是“分步”问题,若完成一件事情必须依次经过多个步骤,每一个步骤的各种方法相互依存,只有各种步骤都完成才算做完成这种事情,则这时用乘法原理

排列数公式推理过程

例:用1、2、3这3个数字可以组成多少个数字十位和个位不重复的两位数?
解:要组成数字不重复的两位数,需要经过两个步骤:第一步确定十位上的数,数字1、2、3都可以放在十位上,共有3种方法;第二步确定个位上的数,因为要求个位数与十位数不能重复,所以个位上的数,只能从三个数字中去掉十位数后所剩的两个数字中任选一个,共有2种方法。只有十位和个位上的数都确定了,才能组成数字不重复的两位数,这两个步骤缺少哪一个都不行。因此,根据乘法原理,3*2=6.

上例中,我们把数字1、2、3称为元素。组成数字不重复的两位数这个问题,从3个不同的元素中任取2个,然后按顺序排成一列数,由于这样的排列与数字不重复的两位数是一一对应的,因此求数字不重复的两位数的个数等同于求这样的排列个数。

推理过程:从n个不同元素中取出m个不同元素排成一列,必须经过m个步骤。
第一步,确定第1个位置上的元素,可以从这n个元素中任取1个放在这个位置上,共有n种方法,即n-(1-1)括号内为位置数减1;
第二步,确定第2个位置上的元素,可以从剩下的n-1个元素中任取1个放在这个位置上,共有n-1种方法,即n-(2-1);
……
第m步,确定第m位置上的元素,第m位置上的元素从剩下的n-(m-1)个元素中任选一个,共有n-m+1种方法。根据乘法原理,全部确定这m个位置的元素共有n(n-1)(n-2)……*(n-m+1)种方法。由于一种方法对应一个排列,所以所有这样排列的个数即排列数。

不可重复排列数公式.png
组合

排列是一个与次序有关的概念,如12,21这两个数字是两个不同的排列,但是在组合里,12和21是一个意思,因为12和21都是由1和2组合而成的,所以顺序并不会影响对组合的判断,因此,组合是与排列概念不同的问题。

从n个不同的元素中,每次取出m个(m<=n)不同元素,不考虑顺序组成一组,叫做从n个元素中每次取出m个元素的组合。这样得出的组合个数称为组合数,记作C (n,m)

求从n个不同元素中取出m个元素的排列数A(n,m),可以按以下两个步骤进行:
第一步,求出这n个不同元素中取出m个元素的组合数C (n,m),
第二步,求出每一个组合中m个元素的全排列数A(m,m),根据乘法原理得出,A(n,m)=C (n,m)*A(m,m),可重复组合公式:C (n,m)=A(n,m)/A(m,m)=n!/m!(n-m)!,
不可重复组合公式:C (n,m)=(m+n-1)!/(m!(n-1)!)
对于实际问题,必须正确判别是排列问题还是组合问题,其区别的关键在于要不要将所取出的元素进行排队。若要排队,则是排列问题,若不要排队,则是组合问题。
以下为组合数计算器python代码。
#!/usr/bin/env python3
# -
- coding: utf-8 -*-

import math
from tkinter import *
class Window:
    def __init__(self, title='组合数计算器', width=300, height=120, staFunc=bool, stoFunc=bool):
        self.w = width
        self.h = height
        self.stat = True
        self.staFunc = staFunc
        self.stoFunc = stoFunc
        self.staIco = None
        self.stoIco = None

        self.root = Tk(className=title)

    def drawCenter(self):
        ws = self.root.winfo_screenwidth()#用户屏幕宽度
        hs = self.root.winfo_screenheight()#用户屏幕高度
        x = int( (ws/2) - (self.w/2) )#距屏幕左边框的像素点数
        y = int( (hs/2) - (self.h/2) )#距屏幕上边框的像素点数
        self.root.geometry('{}x{}+{}+{}'.format(self.w, self.h, x, y))
    
    def createWidgets(self):
        Label(self.root, text="所有元素数n:").grid(row=0,sticky=E)
        Label(self.root, text="取出的元素数m:").grid(row=1,sticky=E)
        Label(self.root, text="不可重复组合数:").grid(row=2,sticky=E)
        Label(self.root, text="可重复组合数:").grid(row=3,sticky=E)
        self.e1 = Entry(self.root)
        self.m = StringVar()
        self.e2 = Entry(self.root,textvariable=self.m)
        self.a1 = StringVar()
        self.e3 = Entry(self.root,textvariable=self.a1)
        self.a2 = StringVar()
        self.e4 = Entry(self.root,textvariable=self.a2)
        self.e1.grid(row=0, column=1)
        self.e2.grid(row=1, column=1)
        self.e3.grid(row=2, column=1)
        self.e4.grid(row=3, column=1)
        self.btnSer = Button(self.root, command=self.click, width=3, height=1,text='运行')
        self.btnSer.grid(row=4,column=1,sticky=E)
        btnQuit = Button(self.root, text='关闭窗口', command=self.root.quit, width=8, height=1)
        btnQuit.grid(row=4,column=2)

    def click(self):
        n=int(self.e1.get())
        m =int(self.e2.get())
        #组合数
        a1=math.factorial(n)/math.factorial(m)/math.factorial(n-m)
        self.a1.set(int(a1))
        #不可重复组合数
        a2=math.factorial(n+m-1)/(math.factorial(m)*math.factorial(n-1))
        self.a2.set(int(a2))
        
    def loop(self):
        self.root.resizable(False, False)   #禁止修改窗口大小
        self.createWidgets()
        self.drawCenter()                       #窗口居中
        self.root.mainloop()

if __name__ == '__main__':
    w = Window(width=350, height=150)
    w.loop()

有5个数字,取两个数字进行组合的计算结果。

组合数计算器.png

推荐阅读更多精彩内容