组合数学基础笔记
加乘原理
加法原理
若 A A A 有 p p p 种方式产生, B B B 有 q q q 种方式产生,则产生 A A A 或B的方式为 p + q p+q p+q。
将加法原理推广到 n n n 件事上:事件 A 1 A_1 A1 有 p 1 p_1 p1 种产生方式,事件 A 2 A_2 A2 有 p 2 p_2 p2 种产生方式 … \dots … 事件 A n A_n An 有 p n p_n pn 种产生方式,则产生 A 1 A_1 A1 或 A 2 A_2 A2 或 … \dots … 或 A n A_n An 有 p 1 + p 2 + ⋯ + p n p_1+p_2+\dots+p_n p1+p2+⋯+pn 种产生方式。
乘法原理
若 A A A有 p p p种方式产生, B B B有 q q q种方式产生,则产生 A A A和 B B B的方式为$ p*q $。
将加法原理推广到 n n n 件事上:事件 A 1 A_1 A1 有 p 1 p_1 p1 种产生方式,事件 A 2 A_2 A2 有 p 2 p_2 p2 种产生方式 … \dots … 事件 A n A_n An 有 p n p_n pn 种产生方式,则产生 A 1 A_1 A1 和 A 2 A_2 A2 和 … \dots … 和 A n A_n An 有 p 1 × p 2 × ⋯ × p n p_1\times p_2\times\dots\times p_n p1×p2×⋯×pn 种产生方式。
排列
选排列
从 n n n 个元素中不重复的选取 m m m 个 ( m ≤ n ) (m\le n) (m≤n) 并进行排列,不同的排列总数记作 A n m A_n^m Anm。排列中的第一个位置有 n n n 种选择,第二个位置有 n − 1 n-1 n−1 种选择 … \dots … 第 m m m 个位置有 n − m + 1 n-m+1 n−m+1 种选择。所以 A n m = n × ( n − 1 ) × ( n − 2 ) × ⋯ × ( n − m + 1 ) = n ! / ( n − m ) ! A_n^m=n\times(n-1)\times(n-2)\times\dots\times(n-m+1)=n!/(n-m)! Anm=n×(n−1)×(n−2)×⋯×(n−m+1)=n!/(n−m)! 。读作“ n n n 的降 m m m 阶乘”。
实现:
//复杂度:O(n),基于通项公式
int permutation(int n, int m) {
int ans = 1;
for(int i = n; i >= m; i--)
ans *= i;
return ans;
}
错位排列
若对于 S ( ∣ S ∣ = k ) S(|S|=k) S(∣S∣=k) 第一个排列 q q q 中 ∀ q i ≠ S i ( i ∈ n ∣ { 1 ≤ n ≤ k } ) \forall q_i\neq S_i(i\in n|\{1\le n\le k\}) ∀qi=Si(i∈n∣{ 1≤n≤k}) 则称 q q q 为 S S S 的错位排列,若 S S S 中任意两个元素互不相等则 S S S 一共有 D ( n ) D(n) D(n)
显然 D ( 1 ) = 0 , D ( 2 ) = 1 D(1)=0,D(2)=1 D(1)=0,D(2)=1 ,现在我们来考察 n = 3 n=3 n=3 的情况
把第 n n n 个元素放在一个位置,比如位置 k k k ,一共有 n − 1 n-1 n−1 种方法
放编号为 k k k 的元素,这时有两种情况:
(1)把它放到位置 n n n,那么,对于剩下的 n − 1 n-1 n−1 个元素,由于第 k k k 个元素放到了位置 n n n,剩下 n − 2 n-2 n−2 个元素就有 D ( n − 2 ) D(n-2) D(n−2) 种方法
(2)第 k k k 个元素不把它放到位置 n n n ,这时,对于这 n − 1 n-1 n−1 个元素,有 D ( n − 1 ) D(n-1) D(n−1) 种方法。
所以 D ( n ) = ( n − 1 ) × [ D ( n − 2 ) + D ( n − 1 ) ] D(n) = (n-1)\times[D(n-2) + D(n-1)] D(n)=(n−1)×[D(n−2)+D(n−1)]
那么我们经行一些推到就可以知道他的通项公式为:
D ( n ) = n ! × ∑ i = 0 n [ ( − 1 ) i i ! ] \displaystyle D(n)=n!\times\sum\limits_{i=0}^n[\frac{(-1)^i}{i!}] D(n)=n!×i=0∑n[i!(−1)i]种排列。
//复杂度O(n)
int derrange(int n) {
int d[10010] = {
0, 0, 1 };
for(int i = 3; i <= n; i++)
d[i] = (i - 1) * (d[i - 1] + d[i - 2]);
return d[n];
}
其实有一个奇奇怪怪的东东:字母 e e e,(自然对数), e = ∑ i = 0 ∞ i ! \displaystyle e=\sum_{i=0}^{\infty}i! e=i=0∑∞i!,他有个奇奇怪怪的特性: e − 1 = ∑ i = 0 ∞ [ ( − 1 ) i i ! ] \displaystyle e^{-1}=\sum^{\infty}_{i=0}[\frac{(-1)^i}{i!}] e−1=i=0∑∞[i!(−1)i]
也就是说 D ( n ) ≈ n ! e \displaystyle D(n)\approx \frac{n!}{e} D(n)≈en!。
那他究竟有多准确那?下面是一组数据。
n D ( n ) ≈ D ( n ) = 1 0.36 0 2 0.73 1 3 2.20 2 10 1 , 334 , 960.91 1 , 334 , 961 \begin{matrix} n&D(n)\approx&D(n)=\\ 1&0.36&0 \\ 2&0.73&1 \\ 3&2.20&2 \\ 10&1,334,960.91&1,334,961 \end{matrix} n12310D(n)≈0.360.732.201,334,960.91D(n)=0121,334,961
使个 r o u n d round round函数,超准的。
//复杂度O(n)
int derrange(int n) {
double e = 2.7182818284590452353602874713527;
double ans = 1;
for (int i = 1; i <= n; i++)
ans *= (double)i;
return round(ans / e);
}
圆排列
从 n n n 个互不相等的元素中选取 m m m 个部分首位的围成一个圆圈的排列叫做圆排列,一共有 A n m m \displaystyle\frac{A_n^m}{m} mAnm种排列。
实现:
//复杂度:O(n),基于通项公式
int circle(int n, int m) {
int ans = 1;
for(int i = n; i >= m; i--)
ans *= i;
ans /= m;
return ans;
}
组合
从 n n n 个元素的集合 S S S 中,无序选出 r r r 个元素,叫做 S S S 的一个r组合。所有不同的组合数个数叫做组合数,记作 C n r C_n^r Cnr 或 ( n r ) \binom{n}{r} (rn) 下面会混着用。
C n r = n ! r ! × ( n − r ) ! \displaystyle C_n^r=\frac{n!}{r!\times(n-r)!} Cnr=r!×(n−r)!n!
我们可以推导几个常用的公式:
-
C n r = C n n − r C_n^r=C_n^{n-r} Cnr=Cnn−r
-
C n r = C n − 1 r + C n − 1 r − 1 C_n^r=C_{n-1}^r+C_{n-1}^{r-1} Cnr=Cn−1r+Cn−1r−1
-
∑ i = 0 n C n i = 2 n \sum\limits_{i=0}^nC_n^i=2^n i=0∑nCni=2n
亲爱的杨辉三角:
0 ≤ k ≤ i 0\le k\le i 0≤k≤i
1 i = 0 C i k 1 1 i = 1 C i k 1 2 1 i = 2 C i k 1 3 3 1 i = 3 C i k 1 4 6 4 1 i = 4 C i k 1 5 10 10 5 1 i = 5 C i k 1 6 15 20 15 6 1 i = 6 C i k \begin{matrix} &&&&&&1&&&&&&&i=0&C^k_i \\ &&&&&1&&1&&&&&&i=1&C_i^k \\ &&&&1&&2&&1&&&&&i=2&C_i^k \\ &&&1&&3&&3&&1&&&&i=3&C_i^k \\ &&1&&4&&6&&4&&1&&&i=4&C_i^k \\ &1&&5&&10&&10&&5&&1&&i=5&C_i^k \\ 1&&6&&15&&20&&15&&6&&1&i=6&C_i^k \\ \end{matrix} 111615