数学 ( 错排问题 )——HUD 2048

来源:互联网 发布:js滤镜效果 编辑:程序博客网 时间:2024/06/10 11:09
  • 题目链接:
    http://acm.hdu.edu.cn/showproblem.php?pid=2048

  • 分析:
    这是一道错排问题,属于组合数学中的问题之一。

    若一个排列中所有的元素都不再自己原来的位置上,那么这样的排列就称为原排列的一个错排。n个元素的错排数记为D(n)。

    错排公式:

    1. 把第n个元素放在一个位置,比如位置k,一共有n-1种方法;

    2. 放编号为k的元素,这时有两种情况:
      ⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;
      ⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;

    3. 综上得到: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!].

    4. 概率公式为: N(n) = (-1)^2/2! + … + (-1)^(n-1) / (n-1)! + (-1)^n/n!

    用容斥原理推导错排公式:

    正整数1, 2, 3, ……, n的全排列有 n! 种,其中第k位是k的排列有 (n-1)! 种;当k分别取1, 2, 3, ……, n时,共有n*(n-1)!种排列是至少放对了一个的,由于所求的是错排的种数,所以应当减去这些排列;但是此时把同时有两个数不错排的排列多排除了一次,应补上;在补上时,把同时有三个数不错排的排列多补上了一次,应排除;……;继续这一过程,得到错排的排列种数为
    D(n) = n! - n!/1! + n!/2! - n!/3! + … + (-1)^n*n!/n! = ∑(k=2~n) (-1)^k * n! / k!,
    即D(n) = n! [1/0! - 1/1! + 1/2! - 1/3! + 1/4! + … + (-1)^n/n!].
    其中,∑表示连加符号,k=2~n是连加的范围;0! = 1,可以和1!相消。

  • AC代码:

#include <iostream>using namespace std;int C;int n;__int64 f[25];void init(){    f[1] = f[0] = 0;    f[2] = 1;     for(int i=3;i<25;i++)    {        f[i]=(i-1)*f[i-1]+(i-1)*f[i-2];    }}int main(){    scanf("%d", &C);    init();    while(C--)    {        scanf("%d", &n);        __int64 sum=1;        for(int i=1;i<=n;i++)            sum*=i;        double ans = (double) f[n]*100/sum;        printf("%.2lf%%\n", ans);    }    return 0;}
0 0