题目链接
- 牛客链接:年会抽奖
- 题目描述:
今年公司年会的奖品特别给力,但获奖的规矩却很奇葩:
- 首先,所有人员都将一张写有自己名字的字条放入抽奖箱中;
- 待所有字条加入完毕,每人从箱中取一个字条;
- 如果抽到的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
现在告诉你参加晚会的人数,请你计算有多少概率会出现无人获奖?
- 输入:
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%
的概率无人获奖。
…
经过慢慢推测,这是一个 错排问题 (百度百科)
错排问题
- 开始有 n 张纸条,下标数字对应纸条上写的名字。
-
当 4 (代表某个人) 拿走了 k 号纸条,那么还有 n - 1 个人;
-
此时 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))
思路
- 求出所有能抽中的结果,也就是 求阶乘;
- 求出 错排的问题 的结果;
- 结果 = 错排结果 / 阶乘结果 。
代码展示
彩蛋
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;
}