神、上帝以及老天爷
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 29703 Accepted Submission(s): 12256
Problem Description
HDU 2006'10 ACM contest的颁奖晚会隆重开始了!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:
首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!
我的神、上帝以及老天爷呀,怎么会这样呢?
不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?
不会算?难道你也想以悲剧结尾?!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:
首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!
我的神、上帝以及老天爷呀,怎么会这样呢?
不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?
不会算?难道你也想以悲剧结尾?!
Input
输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(1<n<=20),表示参加抽奖的人数。
Output
对于每个测试实例,请输出发生这种情况的百分比,每个实例的输出占一行, 结果保留两位小数(四舍五入),具体格式请参照sample output。
Sample Input
1 2
Sample Output
50.00%
省题:
题目中要求求每个人拿到的都不是写自己名字的概率;可知,改题为典型的全错排公式是组合数学中的经典问题,可参考俞勇的《ACM国际大学生程序设计竞赛--知识与入门》中,组合数学的排列问题;可以得到其递推全错排列公式为 : D(n) = (n-1)*(D(n-1)+D(n-2));
分析:
如果同学不知道,旁边也没有资料可以更好的理解,其实可以自己推导下:
当 n=1 的时候也就是说只有一个人的时候,那么他一定可以拿到写了自己的名字的纸条;
当 n=2 的时候(为了方便起见我们给这两个人编号为 a,b,)则他们的名字为 a,b 当纸条进入纸箱又被人抽中的时候,可以得到 所有的可能为
a,b b,a 那么全部都错排的其实就是 b,a了,个数为 1;
当 n=3 的时候 有 a,b,c a,c,b b,a,c
b,c,a c,a,b c,b,a 6种排列方式 那么与原排列(a,b,c)没有任何一个位置重合的就是 (b,c,a)和(c,a,b)两组了 可以推得全错排个数为 2;
同理可以推得 当 n=4 的时候 全错排的个数为 9;
当 n=5 的时候全错排个数为 44;
由此可以推得全错排个数的递推公式为 D(n) = (n-1)*(D(n-1)+D(n-2));
推出了全错排个数的递推公式,那么这种全错排发生的概率就可以求得了 :
P=概率发生的容量 / 事件的总容量;
也就是 P=全错排个数
/ 总的排列个数;
给出代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
long long f[21], sum;
int i, t, n;
f[1] = 0; f[2] = 1;
for (i = 3; i<21; i++)//错排!
f[i] = (i - 1)*(f[i - 1] + f[i - 2]);//错排公式;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
sum = 1;
for (i = 1; i <= n; i++)//N个员工的所写名字的被拿到的可能的全排列;
sum *= i;
printf("%.2lf%%\n", f[n] * 100.0 / sum);//用全排列个数除以错排的个数得到 错排的概率;
}
return 0;
}