年会抽奖(Java 含彩蛋)

题目链接

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

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

1
2
3

  • 输出

0 %
50 %
33.33%

基本思路

首先要正确理解题意,题目求解的是 求无人获奖的概率,也就是说,所有人都没有抽要自己的名字。

  • 只有一个人的时候,百分百中奖。

在这里插入图片描述

  • 两个人的时候,

  • 1 号可能拿了 2 号的纸条,那么 2 号 只能拿 1 号的纸条;

  • 1 号拿了自己的纸条,2 号也拿自己的纸条
    因此无人中奖的概率是 1 / 2 = 50 %
    在这里插入图片描述

  • 三个人的时候

  • 1 号拿了 1 号的纸条,2 号拿了 2 号的纸条,3 号拿了 3 号的纸条;

  • 1 号拿了 1 号的纸条,2 号拿了 3 号的纸条,3 号拿了 2 号的纸条;

  • 1 号拿了 2 号的纸条,2 号拿了 1 号的纸条,3 号拿了 3 号的纸条;

  • 1 号拿了 2 号的纸条,2 号拿了 3 号的纸条,3 号拿了 1 号的纸条;

  • 1 号拿了 3 号的纸条,2 号拿了 1 号的纸条,3 号拿了 2 号的纸条;

  • 1 号拿了 3 号的纸条,2 号拿了 2 号的纸条,3 号拿了 3 号的纸条;

对应关系:

  • 1 == 1, 2 == 2, 3 == 3;
  • 1 == 1, 2 == 3, 3 == 2;
  • 1 == 2, 2 == 1, 3 == 3;
  • 1 == 2, 2 == 3, 3 == 1; 无人获奖
  • 1 == 3, 2 == 2, 3 == 1;
  • 1 == 3, 2 == 1, 3 == 2; 无人获奖
    至少有 2 / 6 = 33.33% 的概率无人获奖。

经过慢慢推测,这是一个 错排问题 (百度百科)

错排问题

  1. 开始有 n 张纸条,下标数字对应纸条上写的名字。

在这里插入图片描述

  1. 当 4 (代表某个人) 拿走了 k 号纸条,那么还有 n - 1 个人;

  2. 此时 k 有两种选择, 拿走 4 号纸条或者其他纸条(比如 3 号纸条);

在这里插入图片描述
我们假设 4号 没有拿到自己名字的纸条,
那么其他 n - 1 个人都有可能拿到 4 的纸条,
而剩下 n - 1 人中,k 可以拿 4 号的纸条,那么剩下 n - 2 人中又可以划分为 n - 2 个子问题;
或者拿其他纸条,那么 n - 1 人中又可以划分为 n - 1 个子问题。
因此得到 递推公式

F(n) = (n-1) * (F(n-1) + F(n-2))

思路

  1. 求出所有能抽中的结果,也就是 求阶乘
  2. 求出 错排的问题 的结果;
  3. 结果 = 错排结果 / 阶乘结果

代码展示

彩蛋

    public static void main1(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()) {
            int n = scanner.nextInt();
            if (n == 1)
                System.out.println("00.00%");
            else if (n == 2)
                System.out.println("50.00%");
            else if (n == 3)
                System.out.println("33.33%");
            else if (n == 4)
                System.out.println("37.50%");
            else if (n == 5)
                System.out.println("36.67%");
            else if (n == 6)
                System.out.println("36.81%");
            else if (n == 7)
                System.out.println("36.79%");
            else if (n == 8)
                System.out.println("36.79%");
            else if (n == 9)
                System.out.println("36.79%");
            else if (n == 10)
                System.out.println("36.79%");
            else if (n == 11)
                System.out.println("36.79%");
            else if (n == 12)
                System.out.println("36.79%");
            else if (n == 13)
                System.out.println("36.79%");
            else if (n == 14)
                System.out.println("36.79%");
            else if (n == 15)
                System.out.println("36.79%");
            else if (n == 16)
                System.out.println("36.79%");
            else if (n == 17)
                System.out.println("36.79%");
            else if (n == 18)
                System.out.println("36.79%");
            else if (n == 19)
                System.out.println("36.79%");
            else if (n == 20)
                System.out.println("36.79%");
        }
    }

搞错了搞错了,哈哈哈哈。再来!

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()) {
            int n = scanner.nextInt();
            float none = method(n);
            float res = none/factorial(n)*100;
            System.out.println(String.format("%.2f",res) + "%");
        }
    }

    /**
     * 动态规划错排问题
     * @param n
     * @return
     */
    public static float function(int n) {
        float[] dp = new float[n+1];
        dp[0] = 0;
        dp[1] = 0;
        dp[2] = 1;
        for (int i = 3; i <= n; i++) {
            dp[i] = (i-1) * (dp[i-1] + dp[i-2]);
        }
        return dp[n];
    }
    /**
     * 递归错排问题
     * @param n
     * @return
     */
    public static float method(int n) {
        if (n == 1) {
            return 0;
        }else if (n == 2) {
            return 1;
        }
        return (n-1) * (method(n-1) + method(n-2));
    }

    /**
     * 递归求阶乘
     * @param n
     * @return
     */
    public static float factorial(int n) {
        if (n == 1) return 1;
        return n * factorial(n-1);
    }

    /**
     * 非递归求阶乘
     * @param n
     * @return
     */
    public static float factorialI(int n) {
        int res = 1;
        while (n > 1) {
            res *= n;
            n--;
        }
        return res;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值