1 : 题目描述
链接:https://www.nowcoder.com/questionTerminal/610e6c0387a0401fb96675f58cda8559
来源:牛客网
2 : 解题思路
大体思路 : 不获奖的概率 == 所有人均未拿到属于自己的名牌 / 所有名牌的排列组合的情况 * 100% 我们可以分别求出分子与分母也就相当于求出了结果 分子 : 所有人均未拿到属于自己的名牌 假设一共有n个人,第一个人没有拿到自己的名牌, 则第一个人有可能拿到的就是剩余的n-1个人中随机一个人的名牌,故有n-1中情况. 而第二个人拿到的名牌情况又可以分为两种 : 1.他拿到了第一个人的名牌 : 此时由于前两个人相互拿到了对方的名牌, 故剩余的情况相当于剩余的n-2个人均未拿到自己名牌的所有组合, 则f(n) = (n-1) * f(n-2); 2.他未拿到第一个人的名牌 : 此时的情况就相当于是剩余n-1个人均未拿到自己名牌的所有组合, 则f(n) = (n-1) * f(n-1); 所有的组合就等于这两种情况的和 则f(n) = (n-1) * f(n-2) + (n-1) * f(n-1) = (n-1) * (f(n-2) + f(n-1)); 分母 : 所有名牌的排列组合情况 假设一共有n个人 第一个人有n个种选择方式,每种选择都要考虑上, 第二个人有n-1种选择方式(第一个人拿走了一个) ...... 不难看出,所有组合的情况==n * (n-1) * (n-2) * ..... * 2 * 1
3 : 实现代码(代码测试过,没问题)
3.1 : 递归
import java.util.Scanner;
public class Main{
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
double x = getUp(n);//得到分子
double y = getDown(n);//得到分母
double ret = x/y*100;
System.out.printf("%.2f",ret);
System.out.println("%");
}
}
private static double getDown(int n) {
double ret=1;
for (int i = 1; i <=n ; i++) {
ret*=i;
}
return ret;
}
private static double getUp(int n) {
if(n<2) return 0;
if(n==2) return 1;
return (n-1) * (getUp(n-1) + getUp(n-2));
}
}
3.2 : 迭代
import java.util.Scanner;
public class Main{
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
//该数组代表有i个人的时候所有人均未获奖的概率
double[]ret = new double[21];//输入数据范围 : 2--20
ret[2] = 50.00;
//该数组代表有i个人的时侯所有人均未拿到自己的号码牌的所有情况
double[]arr = new double[21];
arr[2] = 1;
long t = 2;//注意这里要使用long,否则会溢出
for (int i = 3; i < 21; i++) {
arr[i] = (i-1) * (arr[i-1]+arr[i-2]);//递推公式
t*=i;//求阶乘
ret[i] = (double) arr[i]/t*100;
}
while(sc.hasNext()){
int n = sc.nextInt();
System.out.printf("%.2f",ret[n]);
System.out.println("%");
}
}
}