zoukankan      html  css  js  c++  java
  • 错排

    问题: 十本不同的书放在书架上。现重新摆放,使每本书都不在原来放的位置。有几种摆法?
    这个问题推广一下,就是错排问题,是组合数学中的问题之一。考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。
     
    当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
    第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
    第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;
    综上得到
    D(n) = (n-1) [D(n-2) + D(n-1)]
    特殊地,D(1) = 0, D(2) = 1.
    下面通过这个递推关系推导通项公式
    为方便起见,设D(k) = k! N(k), k = 1, 2, …, n,
    则N(1) = 0, N(2) = 1/2.
    n ≥ 3时,n! N(n) = (n-1) (n-1)! N(n-1) + (n-1)! N(n-2)
    即 nN(n) = (n-1) N(n-1) + N(n-2)
    于是有N(n) - N(n-1) = - [N(n-1) - N(n-2)] / n = (-1/n) [-1/(n-1)] [-1/(n-2)]…(-1/3) [N(2) - N(1)] = (-1)^n / n!.
    因此
    N(n-1) - N(n-2) = (-1)^(n-1) / (n-1)!,
    N(2) - N(1) = (-1)^2 / 2!.
    相加,可得
    N(n) = (-1)^2/2! + … + (-1)^(n-1) / (n-1)! + (-1)^n/n!
    因此
    D(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!相消。
     
    最重要的还是递推式
    D(n) = (n-1) [D(n-2) + D(n-1)]
     
    1.bzoj4563放棋子
    给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在
    这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子
    的限制,求有多少种方案。
     
    /*
    每一行每一列只能放1个求方案数 转化为错排问题
    练习高精压位 压9位。。。
    */
    #include <iostream>
    #include <cstdio>
    #include<iomanip>
    
    #define N 2001
    #define mod 1000000000
    #define _ 9
    #define ll long long
    
    using namespace std;
    ll n;
    struct num
    {
        ll d[N],w;
    /*    void print()
        {
            for (ll i=w;i>=1;i--) cout<<d[i];
            printf("
    ");
        }*/
    }D[N],id;
    
    num operator +(num p1,num p2)
    {
        num ret=id;
        ll g=0;
        if (p1.w<p2.w) swap(p1,p2);
        ret.w=p1.w;
        for (ll i=1;i<=p1.w;i++)
        {
            ret.d[i]=(p1.d[i]+p2.d[i]+g)%mod;
            g=(p1.d[i]+p2.d[i]+g)/mod;
        }
        while(g) ret.d[++ret.w]=g%mod , g/=mod;
        return ret;
    }
    
    num mul(num p1,ll p2)
    {
        num ret=id;
        ret.w=p1.w;
        ll g=0;
        for (ll i=1;i<=p1.w;i++)
        {
            ret.d[i]=(p1.d[i]*p2+g)%mod;
            g=(p1.d[i]*p2+g)/mod;
        }
        while(g) ret.d[++ret.w]=g%mod,g/=mod;
        return ret;
    }
    
    ostream& operator << (ostream &os,num x)
    {
        ll i;
        os<<x.d[x.w];
        for(i=x.w-1;i;i--)
            os<<setfill('0')<<setw(_)<<x.d[i];
        return os;
    }
    
    int main()
    {
    //    freopen("firstmeet.in","r",stdin);
    //    freopen("firstmeet.out","w",stdout);
        scanf("%d",&n);
        if (n == 1)
        {
            puts("0");
            return 0;
        }
        D[1]=id;
        D[2].w=D[2].d[1]=1;
        for (ll i=3;i<=n;i++)
          D[i] = mul((D[i-1]+D[i-2]),i-1);
        //D[n].print();
        cout<<D[n];
        return 0;
    }
    Code

     2.bzoj4517 排列计数

    https://www.cnblogs.com/L-Memory/p/9917967.html

    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    统计nginx日志里访问次数最多的前十个IP
    while 格式化输出 运算符 字符编码
    Python 软件安装
    Python 基础
    Typora 基础的使用方法
    Django ORM (四) annotate,F,Q 查询
    Django 惰性机制
    Django ORM (三) 查询,删除,更新操作
    Django ORM (二) 增加操作
    Django ORM (一) 创建数据库和模型常用的字段类型参数及Field 重要参数介绍
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7551919.html
Copyright © 2011-2022 走看看