问题: 十本不同的书放在书架上。现重新摆放,使每本书都不在原来放的位置。有几种摆法?
这个问题推广一下,就是错排问题,是组合数学中的问题之一。
考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。
错排问题最早被尼古拉·伯努利和欧拉研究,因此历史上也称为伯努利-欧拉的装错信封的问题。
这个问题有许多具体的版本,如在写信时将n封信装到n个不同的信封里,有多少种全部装错信封的情况?
又比如四人各写一张贺年卡互相赠送,有多少种赠送方法?自己写的贺年卡不能送给自己,所以也是典型的错排问题。
错排公式: D(n) = (n - 1) * [D(n - 2) + D(n - 1)] D(1) = 0,D(2) = 1 => D(n) = n! [(-1)^2/2! + … + (-1)^(n-1)/(n-1)! + (-1)^n/n! ] D(0) = 0(所有的元素都放回原位、没有摆错的情况) D(1) = 0(只剩下一个元素,无论如何也不可能摆错) D(2) = 1(两者互换位置) D(3) = 2(ABC变成BCA或CAB) 但是在用公式带入的时候: ans[0] = 1; ans[1] = 0; ans[2] = 1;
试题链接:https://vjudge.net/contest/376400#problem/E
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h>
using namespace std;
long long d[26];
void chu() //错排初始化
{
d[0]=1;
d[1]=0;
for(int i=2;i<=14;i++)
{
d[i]=(i-1)*(d[i-1]+d[i-2]);
}
}
long long C(int n,int x) //求组合数c(n,x);
{
long long sum=1;
for(int i=1;i<=x;i++)
{
sum=sum*(n-i+1)/i;
}
return sum;
}
int main()
{
chu();
int n;
long long ans;
while(cin >> n)
{
if(n==0) break;
ans=0;
for(int i=0;i<=n/2;i++)
{
ans+=C(n,i)*d[i];//累加
// cout << C(n,i) << " " << d[i] << endl;
}
cout << ans << endl;
}
}



京公网安备 11010502036488号