容斥原理
集合的并集
让我们从一个简单的计数问题作为例子出发。在1到100的整数中,我们想数出“是2或3或5的数的倍数”的数的个数,怎么数比较方便呢?我们很容易数出2的倍数的个数、3的倍数的个数、5的倍数的个数,它们分别是100/2=50,⌊100/3⌋=33,100/5=20。但是,不能把它们简单地加起来,因为有的数又是2的倍数又是3的倍数,有的数又是3的倍数又是5的倍数,有的数同时是2,3,5的倍数。所以,我们要把重复的给减掉。同时是2和3的倍数的数的个数为⌊100/(2×3)⌋=16,同时是2和5的倍数的的数的个数为⌊100/(2×5)⌋=10,同时是3和5的倍数的的数的个数为⌊100/(3×5)⌋=6。但是,又不能全都减掉,因为因为同时是2,3,5的倍数的数之前被多加了两次,现在又被减了三次。所以我们最后还需要加上一次⌊100/(2×3×5)⌋=3。综上所述,在1到100的整数中“是2或3或5的数的倍数”的数的个数为:50+33+20−16−10−6+3=74。
上述计数过程的关键在于弄清同时满足多个性质的元素集合之间的交集关系。一个更清晰的办法是用韦恩图表示:设1到100之间2的倍数的集合为A,3的倍数的集合为B,5的倍数的集合为C,求集合∣A∪B∪C∣的大小。在这个问题里,很关键的一点是:我们很容易计算∣A∣,∣B∣,∣C∣,∣A∩B∣,∣A∩C∣,∣B∩C∣,∣A∩B∩C∣这些集合的大小,所以我们希望建立这些集合与A∪B∪C之间的计数关系。从例子中,我们找到了这样一个恒成立的关系:
∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣
上面这个关系可以推广到任意n个集合上:对于有限大小的集合A1,⋯,An,设A={A1,⋯,An},那么:
i∈[n]⋃Ai=J⊆A∑(−1)∣J∣+1Ai∈J⋂Ai
这称为容斥原理(inclusion-exclusion principle)。
“坏性质”
在组合数学中,通常会用到另一种方法来叙述容斥原理。这种方法和上面的“求集合的并集”的形式相比,在本质上是完全相同的。我们下面用新的方法重新叙述容斥原理,并给出证明。
我们可以这样看待容斥原理:在全集U中,有一系列性质是“坏性质”,我们要求出“好元素”——不满足任何坏性质的元素——的个数。注意,一个“性质”就是一个U的子集,这是一种自然语言习惯。通常而言,如果同时满足多个坏性质的元素个数是容易计算的,那么我们就可以用容斥原理求好元素。比如,在上一段的例子中,我们就把“2的倍数”、“3的倍数”、“5的倍数”分别看作三个坏性质,那么只要求出好元素的个数(既不是2的倍数也不是3的倍数也不是5的倍数),再取补集就得到了答案(2或3或5的倍数)。用记号表示:在给定的一个大集合U中,设坏集合为A1,⋯,An。已知∣i=1⋂kApi∣是容易计算的,目标就是计算出∣i=1⋃nAi∣。令A={A1,⋯,Am}。对任意J⊆A,定义:
N=(J):=∣{x∈U∣∀Ai∈J,x∈Ai且∀Ai∈A∖J,x∈/Ai}∣
N=(J)表示所有满足J中的所有坏性质,而不满足任何其它坏性质的元素个数。比如在刚才的例子中,把三个坏性质“2的倍数”、“3的倍数”、“5的倍数”分别记为A1,A2,A3,那么N=({A1,A3})就表示“既是2的倍数又是5的倍数,但不是3的倍数”的数的个数(也就是∣(A1∩A3)∖A2∣)。注意到,N=(∅)就表示不满足任何坏性质的元素个数,也就是“好元素”个数。对任意J⊆A,定义:
N≥(J)=∣{x∈U∣∀Ai∈J,x∈Ai}∣
N=(J)表示所有满足J中的所有坏性质的元素个数,它其实就相当于Ai∈J⋂Ai的大小,只不过J=∅时N≥(∅)表示全集而不是空集。在可以使用容斥原理的问题中,N≥(∅)通常是容易求出的。
“N=和N≥的定义”也完全可以用“坏性质集合间的交集、并集”来描述,但是要注意边界条件:“满足0个坏性质”对应的是全集,而不是空集。
在这样的记号下,容斥原理的表述为:
N=(∅)=J⊆A∑(−1)∣J∣N≥(J)
计算时可以写为:(其中(jA)表示全体大小为j的A的子集)
N=(∅)=j=0∑m(−1)jJ∈(jA)∑N≥(J)
证明:我们考虑每个元素的“贡献”(“贡献”是计数中的一种证明方法,上面的等式的左右两边都是在数数,要证明等式相等,只需证明任意x∈U被等式左边数到的次数和被等式右边数到的次数是相等的)。如果x∈N=(∅),将在左侧贡献1。这意味着x不属于任何坏集合,因此它在右侧只会在j=0时(即J=∅)时被统计到,刚好在N≥(∅)中贡献1次;如果x∈/N=(∅),那么左侧贡献0,此时x可能出现在了某几个坏集合中,不妨设出现在Ai1,⋯,Ait中,那么当且仅当J⊆{Ai1,⋯,Ait}时(包括空集)右侧才会贡献,总的贡献恰好为j=0∑t(−1)j(jt),由二项式定理,这恰好等于j=0∑t(jt)(−1)j(1)t−j=(−1+1)t=0。证毕。
我们可以证明更一般的容斥原理。对于任意S⊆A:
N=(S)=J:S⊆J⊆A∑(−1)∣J∣−∣S∣N≥(J)
证明:考虑每个元素的贡献。∀x∈N=(S),左边贡献1;等式右边当且仅当x∈N≥(J)才产生贡献,这要求J⊆S。而S⊆J,因此必须有S=J。因此等式右边也恰好贡献1。如果x∈/N=(S),则左边贡献0;等式右边,如果本身就有S=A,则右侧等式直接可以写作N≥(A)=N=(A),等式成立。如果S⊊A,此时分类讨论:①∃Ak∈S,x∈Ak,那么因为S⊆J,所以对于所有等式中的J,N≥(J)的贡献都为0,成立。②∀Ak∈S,x∈Ak同时∃Ak∈J∖S,x∈/Ak。此时,记Tx={Ai∈A∣x∈Ai},那么当且仅当J⊆Tx,N≥(J)才产生贡献。所以,等式右侧的贡献为S⊆J⊆Tx∑(−1)∣J∣−∣S∣N≥(J)=j=∣S∣∑∣Tx∣(−1)j−∣S∣S⊆J∈(jTx)∑N≥(J) =j=0∑∣Tx∣−∣S∣(−1)j(j∣Tx∣−∣S∣)=(−1+1)∣Tx∣−∣S∣=0。证毕。
容斥原理的应用
错位排列
一个排列{ai}i=1n是错位排列当且仅当∀i∈[n],ai=i。求长度为n的错位排列的个数fn。
设全集为U,共包含n!个排列。对任意i∈[n],把所有满足ai=i的排列集合看作坏性质Ai。那么,容易发现N≥({Ai1,⋯,Ait})=(n−t)!
代入容斥原理的公式,N=(∅)=j=0∑n(−1)jJ∈(jA)∑(n−j)!=j=0∑n(−1)j(jn)(n−j)!。所以
fn=j=0∑n(−1)j(jn)(n−j)!
这就是错位排列的通项公式。
第二类斯特林数通项
“k个球放进n个箱子,球不同,箱子相同,箱子不能为空”的答案是第二类斯特林数{kn}。我们还证明过,“k个球放进n个箱子,球不同,箱子不同,箱子不能为空”的答案是{kn}n!,因为只需在箱子相同的答案的基础上对箱子做轮换即可。现在我们利用容斥原理来计算后面这个小球装箱问题,由此给出第二类斯特林数的通项公式。
“k个球放进n个箱子,球不同,箱子不同,箱子不能为空”可以看作:求“从[k]到[n]的满射”的个数。从[k]到[n]的映射共有nk个,把这看作全集U。对于任意i∈[n],把“i没有被映射到的映射”看作坏性质集合Ai,那么有N≥({Ai1,⋯,Ait}) =(n−t)k。于是有N=(∅)=j=0∑n(−1)jJ∈(jA)∑(n−j)k=j=0∑n(−1)j(jn)(n−j)k。
综上,我们得到:
{kn}=n!1j=0∑n(−1)j(jn)(n−j)k
二分图完美匹配
给定2n个顶点的二分图,二分图的两侧各n个节点。设Ai1,i2表示左侧的第i1个点与右侧的第i2个点直接是否有边相连(有则为1,无则为0)。一个“完美匹配(perfect match)”是n条边,分别连接左右的全部点。给定邻接矩阵,我们可以枚举n上的全排列σ,计算该二分图上的完美匹配方案数:σ∑i=1∏nAi,σ(i)。这样做的计算复杂度为O(n!⋅n)
我们可以利用容斥原理计算完美匹配方案数。把n!种全排列看作全集U。把“右侧的节点i没有被匹配上的匹配”看作坏性质集合Ai,那么N≥(J)=i=1∏n(j∈[n]\J∑Ai,j)。于是有N=(∅)=J∈A∑(−1)∣J∣i=1∏n(j∈[n]\J∑Ai,j)。用这个式子计算,不再需要枚举全排列,只需要枚举大小为n的集合的子集。如果对后面部分做好预处理,复杂度可以达到O(2n⋅n)。可以证明,在渐进意义下这是最优复杂度了。
参考资料
[1] Chihao Zhang, Combinatorics in Computer Science (Spring 2023)