公式
- 普通阶乘
$$
D_n=|I|-\sum_{i=1}^n|S_i|+\sum_{i=1}^n\sum_{j>i}|S_i∩S_j|-\sum_{i=1}^n\sum_{j>i}\sum_{k>i}|S_i∩S_j∩S_k|+…+(-1)^{n-1}|S_1∩S_2∩…∩S_n|
$$
$$
=n!(1-\frac{1}{1!}+\frac{1}{2!}-\frac{1}{3!}+…+(-1)^{n}\frac{1}{n!})
$$
- 递推关系
$$
D_n=(n-1)(D_{n-1}+D_{n-2}),D_1=0,D_2=1
$$
$$
D_n=nD_{n-1}+(-1)^n
$$
三种生成方式
递归
时间复杂度为$O(D_n)$,但是由于递归函数的调用开销是很大的,系统要为每次函数调用分配存储空间,并将调用点压栈予以记录。而在函数调用结束后,还要释放空间,弹栈恢复断点。所以,考虑函数处理过程,整体看来,递归法的效率并不高。
1 | void Digui(int n,int cur,int vis[]) //递归 |
字典序生成法
用全排列的字典序生成法,同时对每次生成的全排列检验是否合法。
时间复杂度$O(2n*n!)$
1 | void Dictionary(int n) //字典生成 |
改进的字典序生成法
在对于某一个生成的全排列时判断,同时对接下来不正确的全排列都跳过。由于这种额外的判断方式,我们不能再使用next_permutation函数。
时间复杂度$O(D_n)$
1 | int AdLxOrder(int n) |