错排介绍
n个有序的元素有n!种排列方式,如果一个排列使得所有元素都不在原来的位置上的排列就叫错排。
错排推导
(1)错排有两种方法进行计算,一种是基于容斥定理最后得出来的一个阶乘的计算式,计算机对于阶乘非常的不友好,因此第一种很少使用。
(2)由于阶乘的原因,我们不得不再寻找一种计算错排Dn的方法。
首先我们以1,2,3,4的错排为例子,
(1,2)的错排唯一,是(2,1)
(1,2,3) 的错排是 (3,1,2) 和 (2,3,1)。这两种都可以看作是 (1,2) 的错排的每一位元素和3进行交换位置得到。如图
(1,2,3,4) 的错排可以表示为
(4,3,2,1) 前三个总结为4与1,2,3,分别换位,另外两个元素错排
(3,4,1,2)
(2,1,4,3)
(4,1,2,3) 中间三个是4和3,1,2(1,2,3的错排一种)每一位进行交换
(3,4,2,1)
(3,1,4,2)
(4,3,1,2) 最后三个是4和2,3,1(1,2,3的错排的另外一种)每一位进行交换得到
(2,4,1,3)
(2,3,4,1)
由上面可以得到错排的第二种方法:
从1,2,3…n中任取一个数字i,分别和其他的n-1个数中的随便一个互换,然后剩下的n-2个数字进行错排,共得到(n-1)Dn-2种错排。还有就是 i 以外的n-1个数字进行错排,i和n-1的错排中的每一个数字进行交换,共得到(n-1)Dn-1个错排。最后结果为二者加起来。
Dn = (n-1)(Dn-1 + Dn-2) (D1 = 0, D2 = 1)
通过这个递归公式就能很轻松的求出来错排结果了。
例题地址
例题讲解
非常直观的错排题,只要注意别用int就行了,还需要注意的是再printf中输出%需要打两个%%。
AC代码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int ans;
scanf("%d", &ans);
while (ans--)
{
int n;
scanf("%d", &n);
double a[30];
double sum = 1;
memset(a, 0, sizeof(a));
a[1] = 0;
a[2] = 1;
for (int i=1; i<=n; i++)
sum*=i;
for (int i=3; i<=n; i++)
a[i] = (i-1) * (a[i-1] + a[i-2]);
printf("%0.2lf%%\n", a[n]*100/sum); //两个百分号才能输出一个百分号
}
return 0;
}