递推总结


递推总结

错排公式

介绍

问题:现有10本书按照顺序摆放,现要求重新排列,使得新的书的顺序中每一本书都不在原来的位置,求有多少种排列方式?

这个问题推广一下,就是错排问题,是组合数学中的问题之一。考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题

OK,现在详细分析这个问题,我们要的最终结果就是书的编号与所在位置的编号不同,在这里,我们把n本书的错排操作数记为D(n),那n-1本就是D(n-1)n-2本就是D(n-2)啦,下面,我们把放置问题分为两步(初始位置号与书的编号相同):

第一步:

  • 我们取一本书,书的编号为m,现在这本书就在我们手中,注意,按照题目要求,最开始的时候这本书的位置号也是m号,按照题目要求,我们现在放书时不能放回这个位置m了,而是要选择其他位置,那么有多少种选择呢?
  • 想一下,总共有n本书,n个位置,现在我手里这本书不能把它放到位置m,那么剩下的n-1个位置我当然就是随便扔啦,也就是n-1种扔法,好,现在,我选择了位置k,我决定把手里这本书放到位置k这里,记住这个是位置编号k,那么,我肯定要把原来这里的编号为k的书拿出来,再把这本编号为n的书放进去喽。所以,现在我们手里的书的编号是k。

第二步:

  • 我们把手里这本编号为k的书本放到书架,注意,放的过程中我们又面临两种情况,可以想到,此时此刻现在书架上编号m的位置是空着的,所以我们可以选择放在这个位置上,书的编号为k,位置编号为m,没错,满足题意,这是第一种情况,还有一种就是我不选择这个空着的位置m,我再重新选择一个新的位置,我们称之为第二种情况,下面详细分析

  • 第一种情况:我把这本编号为k的书放到这个编号为m的地址,那现在我们面前是什么状况呢,就是位置k和位置m的书交换位置,也就是位置号不等于书号,即满足错排,总共n个位置,我们只动了m和k这两个位置,那么剩下的n-2个位置还是纹丝不动,保持一一对应的关系呢

    ​ 那么对于剩下的这n-2本书的错排操作,我们又回到了问题的起点,求n-2本的错排操作数D(n-2),结合第一步,我们可以得到第一种情况总共有(n-1)*D(n-2)种方法

  • 第二种情况:我们不选择这个空着的位置m啦,我们手持这本编号为k的书,我们从除了位置m以及位置k的剩下的n-2个位置中选择一个位置。

    ​ OK,我们现在开始想,我手里这本书不能放在这个位置m,嗯嗯,除了第一步我们放置的那本书m不用管了,我们还要搞手里这本和剩下的n-2本,也就是n-1本,同时又要求手里这本k还不能放到位置m,这是不是就相当于把手里这本加上剩下的n-2本也就是n-1本书进行错排呢?

    ​ 哇哇哇,想一想,错排的定义,要求每本书都不能呆在某一个特定位置,是不是刚好符合呢QWQ,所以,现在的为题就到了求手里这本和剩下的n-2本总共是n-1本书的错排操作数,我们记为D(n-1),结合第一步,我们得出这第二种情况共有(n-1)*D(n-1)种方法

好的,现在我们总结两种情况,结果进行相加,就可以得到递推公式啦
递推公式为:D(n)=(n-1)*(D(n-1)+D(n-2))

例题

1、神、上帝以及老天爷

#include<iostream>
#include<algorithm>
using namespace std;
long long func(int n)//计算阶乘
{
    long long sum=1;
    for(int i=2;i<=n;i++)sum*=i;
    return sum;
}
int main()
{
    long long f[30]={0};//长整型数组用来存放错误的抽取
    f[1]=0;
    f[2]=1;
    for(int i=3;i<21;i++)f[i]=(i-1)*(f[i-1]+f[i-2]);//递推公式
    //以上进行预处理
    int c,n;
    cin>>c;
    while(c--)
    {
        cin>>n;
        double ans=f[n]*100.0/func(n);
        printf("%.2f%%\n",ans);//主义输出格式
    }
    return 0;
}

参考

https://blog.csdn.net/bengshakalakaka/article/details/83420150

组合+错排

例题

2、不容易系列之(4)——考新郎

#include<iostream>
#include<algorithm>
using namespace std;
int c,m,n;
long long f[25];
long long C[25];
int main()
{
    f[1]=0;
    f[2]=1;
    for(int i=3;i<=20;i++)
    {
        f[i]=(i-1)*(f[i-1]+f[i-2]);
    }
    C[0]=1;C[1]=1;C[2]=2;
    for(int i=3;i<=20;i++)
    {
        C[i]=C[i-1]*i;
    }
    cin>>c;
    while(c--)
    {
        cin>>n>>m;
        cout<<C[n]/C[m]/C[n-m]*f[m]<<endl;
    }
    return 0;
}

单纯地递推

例题

3、折线分割平面

思路:列举找规律

第1条折线,穿过0条线,多了1个区间;

第2条折线,穿过2条线,多了5个区间;

第3条折线,穿过4条线,多了9个区间;

第4条折线,穿过6条线,多了13个区间;

多的区间: 2*2*(n-1)+1

#include<iostream>
#include<algorithm>
using namespace std;
long long ans[10005]={0,2,7};
int main()
{
    for(int i=3;i<10005;i++)ans[i]=ans[i-1]+4*(i-1)+1;
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        cout<<ans[n]<<endl;
    }
    return 0;
}

文章作者: Amonologue
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Amonologue !
  目录