题目描述:
输入描述:
输入包含多组数据,每组数据包含一个正整数n(2≤n≤20)。
输出描述:
对应每一组数据,以“xx.xx%”的格式输出发生无人获奖的概率。
示例1:
输入:
2
输出:
50.00%
题目分析:
这个题实际上是一个错排的问题,下面用一个例子来说一下这个题目的思路。
用A,B,C…表示n个写着友人名字的信封,同a,b,c…表示n份写好的信纸,把错装的总数记为D(n)。
假设把a错装在B里面了,那么这种情况下对应着两种情况:
- 把b装在A里面了,这时每种装错的其余的部分都与a,b,A,B无关了,即有D(n-2)种装错法
- 还有一种情况是将b装在除A,B之外的信封里面了,这时装信工作实际是把n-1份信纸装在n-1份信封里面的操作,即有D(n-1)种错装法
将a装在B里面的两种情况加起来就有D(n-1)+D(n-2)种错装法
但是,a装在除了A之外的每一个信封里面都有上面的两种情况,即所有的错装的情况一共有:(n-1)*(D(n-1)+D(n-2))种错装法!!!
所有的组合的可能是n*(n-1)*…*1
用错装的/所有的可能的组合 = 最终的结果
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long r[] = new long[21]; //没有领到奖品的人数,即装错的个数
long f[] = new long[21]; //总共有多少种可能,共有多少种排列组合
r[0] = 0; //没有信封没有信就不会出错,即0个人就不可能装错
r[1] = 0; //1个信封1封信不可能装错,即1个人不可能领不到奖品
r[2] = 1; //2个信封2封信装错的有1种可能,即2个人抽名字只有1种情况所有人不能抽到自己的名字
f[0] = 1; //0个信封0封信,即0个人不会有抽取的可能
f[1] = 1; //1个信封1封信,只有1种组合
f[2] = 2; //2个信封2封信,有2种组合
for (int i = 3; i < r.length; i++) {
r[i] = (i-1)*(r[i-1]+r[i-2]); //上面的分析过程得出来的结论
f[i] = f[i-1]*i;
}
while (sc.hasNext()) {
int n = sc.nextInt();
System.out.printf("%.2f%%\n",100.0*r[n]/f[n]); //注意输出的格式
}
}
}