一、题目
今年公司年会的奖品特别给力,但获奖规则却很奇葩:
1.首先,所有人员都将一张写有自己名字的字条放入抽奖箱中;
2.待所有字条放入完毕,买人从箱子中取一个字条;
3,现在抽到的字条写的就是你的名字,那么“恭喜你,中奖了!”;
4.现在告诉你参加晚会的人数,请你计算有多少概率会出现无人获奖?
二、思路
这道题在问出现无人获奖的概率,无人获奖就是说每个人都没有抽到正确的结果(自己)。很明显其概率就应该是无人获奖的情况数 / 所有的可能。
n个人不放回的抽奖,所有可能的结果为n的阶乘。
如果每个人都不中奖,那么只要确保n个元素不在原有中奖位置即可,那么问题转化为如何错排n个元素。 我们根据的是错排来推导出递推公式来计算。
错排问题是组合数学发展史上的一个重要问题,错排数也是一项重要的数。令 是 的一个错排,如果每个元素都不在其对应下标的位置上,即 ,那么这种排列称为错位排列,或错排、重排(Derangement)。
递推公式
第一步:考虑第n个元素,把它放在某一个位置,比如位置k,一共有n-1种方法;
第二步:考虑第k个元素,这时候有两种情况:
(1)把它放在位置 n,那么对于除 n 以外的 n-1 个元素,由于第k个元素放在了位置n,所以剩下n-2个元素的错排即可。有D(n-2)种放法
(2)第k个元素不放在位置n,这时对于这n-1个元素的错排,有D(n-1)种放法。
根据乘法和加法法则,综上得到:
三、代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
// 输入一个正整数
int n = scanner.nextInt();
long sum1 = factorial(n);
long sum2 = count(n);
// 将得到的分子分母进行相除,就能到的概率
double res = (sum2*1.0/sum1) * 100;
System.out.println(String.format("%.2f", res) + "%");
}
}
// 错排算法
private static long count(int n) {
if (n == 1) {
return 0;
} else if (n == 2) {
return 1;
}
return (n - 1) * (count(n - 1) + count(n - 2));
}
// n 的阶乘
private static long factorial(int n) {
long res = 1; // int 类型不行
for (int i = 1; i <= n; i++) {
res *= i;
}
return res;
}
}