错排问题,这个问题的背景可能有多种表述方式,将其形式化,可表为:将 1 至 n 这 n 个数字排列,使得每个数字不出现在其所在序号的位置上,问所有可能的排列数。详见 wiki
对于这一问题的「官方」解法是这样的:考虑编号为 1 的数字,显然它有 \(n-1\) 个可能的位置。假定它出现在 i 位置上,那么分两种情况考虑:
综上,可以得到递推公式,\(D(n)=(n-2)(D(n-1)+D(n-2)), n\ge 3\)。当然,初始条件为 \(D(1)=0, D(2)=1\)。
另一种也比较容易想到的方法是这样的:对于所有可能的排列,减去其中出现矛盾的情况。
综上,递推公式为 \(D(n)=n!-C_n^1D(n-1)-C_n^2D(n-2)-...-C_n^{n-2}D(2)-1, n\ge 3\),初始条件和上种解法一致。
from scipy.special import comb
import math
def derangement_1(n):
if n == 1:
return 0
if n == 2:
return 1
return (n-1) * (derangement_1(n-1)+derangement_1(n-2))
def derangement_2(n):
if n == 1:
return 0
if n == 2:
return 1
der = math.factorial(n)
for i in range(n-1, 1, -1):
der -= comb(n, n-i) * derangement_2(i)
return int(der-1)
m = 15
for i in range(2, m):
print(derangement_1(i), end=" ")
print()
for i in range(2, m):
print(derangement_1(i), end=" ")
结果为
1 2 9 44 265 1854 14833 133496 1334961 14684570 176214841 2290792932 32071101049
1 2 9 44 265 1854 14833 133496 1334961 14684570 176214841 2290792932 32071101049
可见,两种计算方法是一致的。
原文:https://www.cnblogs.com/easonshi/p/12088684.html