错排问题分析

前言

错排问题,是一种著名且常见的算法,应该熟练掌握它

结合例题进行分析

今年公司年会的奖品特别给力,但获奖的规矩却很奇葩:

  1. 首先,所有人员都将一张写有自己名字的字条放入抽奖箱中;
  2. 待所有字条加入完毕,每人从箱中取一个字条;
  3. 如果抽到的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
    现在告诉你参加晚会的人数,请你计算有多少概率会出现无人获奖?
    题目链接

分析:
概率 = 每个人拿到的不是自己名字的排列总和 / 每个人有可能拿到的名字的排列总和;

分母,是要求得所有可能出现的情况,很显然是一个全排列问题,即为n!

接下来对分子进行分析:
设f(n)表示有n个人时,错排的方式

1.第一个人,先将其错排 -> 将他放在 2~n的位置上,总共有n-1种方法

2.假设第一个人放的位置是k,加下来再对k进行分析:

a.可以将k放在1的位置,那么剩余n-2个元素的排列方法为 f(n-2)

b.不将k放在1的位置,接下来剩余 n-1个元素和n-1个位置,此时可以将第1个位置看成第k个位置,即将要放在第k个位置的元素,可以放到第一个位置上,此时有f(n-1)种方法 -> 完成第二步的方法为 f(n-1) + f(n-2 )

完成一二步的所有方法为 (n-1) * [f(n-1) + f(n-2) ]

综上所述:
f(n) = (n-1)*[f(n-1) + f(n-2 )] 当 n=1时,f(1)=0; n=2时,f(2)=1;

实现代码:

#include 
using namespace std;

double GetSum(int n)//获得所有的排列数
{
     
    if(n<3)
        return n;
    return n*GetSum(n-1);
}

double GetNum(int n)//获得排错的总数
{
     
    if(n==1)
        return 0;
    if(n==2)
        return 1;
    
    return (n-1)*(GetNum(n-2)+GetNum(n-1));
}

int main()
{
     
    double n;
    while(cin>>n)
    {
     
       double num=GetNum(n)/GetSum(n)*100;
        printf("%.2f%\n",num);
    }
    
    
    return 0;
}

你可能感兴趣的:(算法,错排问题)