PAT乙级(Basic Level)练习题 年会抽奖

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

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

输入描述:
输入包含多组数据,每组数据包含一个正整数n(2≤n≤20)。

输出描述:
对应每一组数据,以“xx.xx%”的格式输出发生无人获奖的概率。

输入例子:

2

输出例子:

50.00%

\color{blue}解题思路:
解这道题,我们需要明白什么时候才算做都不获奖全部都不获奖的概率如何计算
对于什么时候才算做都不获奖,当然是所有人都拿到了别人的名字,没有拿到自己的名字。
全部都不获奖的概率必定是由 n个人都拿错的情况种数n个人拿出的所有排列情况数
n个人拿出的所有排列情况数显然是n的阶乘。
n个人都拿错的情况种数与上一道题 PAT乙级(Basic Level)练习题 发邮件 是一样的。
假设a的名字没有被a拿到,其他n - 1个人都有可能拿到,即有n - 1种情况。假设b拿到了a的名字,那么对于b的名字有两种情况,

第一种是b的名字被a拿到了,也就是ab互相拿到了对方的名字,那么对于其他n - 2个人互相拿错又是一个子问题f(n - 2).

第二种是b的名字没有被a拿到,则剩下的问题是子问题f(n - 1).
因此可得递推公式f(n) = (n - 1) * (f(n - 1) + f(n - 2)).

最终得出公式n人都不获奖的概率h(n) = (n - 1) * (f(n - 1) + f(n - 2)) / (n!).
\color{blue}代码实现:

#include <iostream>
#include <math.h>
using namespace std;

int main(int argc, const char * argv[]) {
    int n = 0;
    //fTable[n]记录n个人都拿错(全不获奖)的情况种数,allTable[n]记录所有可能的组合情况n的阶乘
    long long fTable[21] = {0, 0, 1}, allTable[21] = {0, 1, 2};
    for (int i = 3; i < 21; ++i) {
        //递推计算i个人全部拿错
        fTable[i] = (i - 1) * (fTable[i - 1] + fTable[i - 2]);
        //递推计算i的阶乘
        allTable[i] = i * allTable[i - 1];
    }
    //scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1
    while (scanf("%d", &n) != - 1) {
    	//注意%属于控制字符,两个连续的%%才表示真正的%字符
        printf("%4.2lf%%\n", 100 * double(fTable[n]) / allTable[n]);
    }
    return 0;
}

在这里插入图片描述

发布了1005 篇原创文章 · 获赞 269 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/104688841