您的位置:首页 > 其它

【组合数学】“派送食物问题”

2015-04-01 08:47 302 查看

题目

问题描述
Lucy 和Lily 是一对双胞胎,在Lucy 和Lily 十岁生日的时候,她们举办了一个晚会。晚会上,Tom 负责派送食物。Tom 手上有两种食物,汉堡和三明治。晚会上的20 个孩子围成一圈,Tom 拿了10 个汉堡和10 个三明治,进行分发。为了保证公平,Tom 采用丢硬币的方法,正面给汉堡,背面给三明治。Lucy 和Lily 被按排到最后再拿食物,但当Tom 发到第19 个人Lucy 的时候,这时候只有两个汉堡了,于是他不再丢硬币了,让最后两个人都拿汉堡。Lucy 和Lily 因此都拿了汉堡。
对此,Tom 很好奇,他非常想知道当n(n 为偶数)个人围成一圈的时候,分发n/2 个
汉堡,n/2 个三明治,Lucy 和Lily 最后两个拿食物,她们拿到同样食物的概率。
数据输入
第一行整数k,测试数据的组数,接下来k 行,每行一个偶整数n。其中,n 的取值范围是[2,4,6…100000]。
数据输出
对于每组测试数据,输出Lucy 和Lily 拿到同样食物的概率。输出四舍五入保留3 位有
效数字。
样例输入输出
样例输入
3
6
10
256
样例输出
0.625
0.727
0.950
数据说明
30%的测试数据n 的取值范围小于50。
70%的测试数据n 的取值范围小于等于1000。
100%的测试数据n 的取值范围小于等于100000。


这完全就是一道数学题啊。。。由于我十分愚钝,丝毫不会。。。

我们先把题解发出来

所以最后两个数不同的概率是C(n-2,n/2-1)*(1/2)^(n-2)。
因此,最后两个数相同的概率就是
1- C(n-2,(n/2-1)*(1/2)^(n-2)。
由于n实在太大了,在计算的时候要注意乘法和除法的结合,既要避免浮点数溢出,又要避免精度降到0之下。


上来那个“所以”弄得我莫名其妙,不知道这式子怎么蹦出来的(当然神犇们一看题一眼就会了)。下面给出我愚蠢的过程。

我先敲了如下的模拟(数学课本上说,不好算的概率,可以用计算机模拟)

var
a,b,tot,i,c,n:longint;
begin
randomize;
tot:=10000000;
c:=0;
n:=10;
for tot:=1 to tot do
begin
a:=n>>1;b:=n>>1;
for i:=1 to n-2 do
if random(2)=1 then dec(a) else dec(b);
if (a<=0)or(b<=0) then inc(c);
//if (a=0)or(b=0) then inc(c);
end;
writeln(c/tot:0:3);
end.


这个模拟充斥着我迂腐的思想。。。我在注释的那一行纠结了很长时间,后来觉得就是小于等于零,而不是等于零,因为小于零对应着某一种“提前取完”。(其实把样例输进去看下就知道了“)。

通过这个模拟我们发现符合要求的情况就是n-2个数,每个可以取0或1,取得大于等于n/2个0或1。


这样就和题解上的一样了,就剩下”由于n实在太大了,在计算的时候要注意乘法和除法的结合,既要避免浮点数溢出,又要避免精度降到0之下”的处理,我又用了愚蠢的方法,把组合数定义里的所有分子分母存起来,先乘法,太大之后做除法。

var
t,n:longint;
x,y:array[0..300000]of longint;

function calc(n:longint):extended;
var i,j,a,b:longint;ans:extended;
begin
b:=n-2;
for i:=1 to b do y[i]:=2;
a:=n>>1-1;
for i:=1 to a do
begin
x[i]:=n-1-i;
inc(b);
y[b]:=i;
end;
ans:=1;
i:=1;
j:=1;
//for i:=1 to b do write(y[i],' ');
while i<=a do
begin
ans:=ans*x[i];
while (ans>1e15)and(j<=b) do begin ans:=ans/y[j];inc(j);end;
inc(i);
end;
while j<=b do
begin
ans:=ans/y[j];
inc(j);
end;
exit(1-ans);
end;

begin
assign(input,'food.in');reset(input);
assign(output,'food.out');rewrite(output);
readln(t);
for t:=1 to t do
begin
read(n);
writeln(calc(n):0:3);
end;
close(input);close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: