今天有人发了一道初中数学题:

就是4只鸭子在一个圆,求他们在一个半圆的概率。
其实如果用半径和弧度来表示鸭子的位置,可以避开平面坐标二次项的麻烦。
而且显然鸭子是否属于一个半圆只与它们的弧度有关,与它们距离圆心的距离无关。
4只鸭子属于一个半圆的充要条件:其中一只鸭子顺时针转180度,或逆时针转180度,可以扫遍其它的鸭子。
按照这个思路不难写出程序:
set.seed(100)
n <- 1000000
angle <- matrix(runif(n*4, 0, 360), nrow=4)
max.angle <- apply(angle, 2, max)
min.angle <- apply(angle, 2, min)
reverse.angle <- ifelse(angle>180, angle-360, angle)
max.reverse <- apply(reverse.angle,2,max)
min.reverse <- apply(reverse.angle,2,min)
sum(max.angle-min.angle<180 | max.reverse-min.reverse<180)/n
结果就是0.5.
如果用python是这样:
import numpy as np
def duck_guess():
s = e = 1000000
r = 0
while(e > 0):
e = e - 1
d = np.random.uniform(0,360,(1,4))[0]
d = np.sort(d)
angle = -1
delta = 0
for x in range(d.size):
if(angle >0 and delta < d[x] - angle):
delta = d[x] - angle
angle = d[x]
if(delta >= 180):
r = r + 1
elif(d[0]+ 360 - d[-1:] >= 180):
r = r +1
print(r*1.0/s)
duck_guess()
答案也是0.5,但python代码长很多,运行时间慢很多。如果想学习编程的家长和小朋友,注意了。
当然,还有更简单一些的方法。前面4只鸭子都是随机的,因此会有顺时针和逆时针两种可能;但如果固定了其中第一只鸭子,那么四只鸭子练成半圆就只有一种可能了,就是穿过第一只鸭子那种方案。于是可以写成第二个程序。
angle <- rbind(matrix(runif(n*3, 0, 360), nrow=3), rep(180,n))
max.angle <- apply(angle, 2, max)
min.angle <- apply(angle, 2, min)
sum(max.angle-min.angle<180)/n
结果自然也是0.5的。
有人说初中生不懂编程怎么办?其实也可以手算。
比如先固定一只鸭子,连圆心作一条直径,那么其它3只鸭子都在它左边,或者都在它右边的概率都是0.5^3=0.125,因为3只鸭子的位置是独立的,因此,加起来是0.25;
最后一种情况是左边和右边分别有1只或2只,但不相等,恰好在直径上的概率是0,可以忽略。
假设1只在左边,两只在右边,左边是a1,a1<0,右边是a2,a3>0,那么我们知道,如果a1固定了,则需要0<a2<a1+0.5,0<a3<a1+0.5,而由于a2、a3是独立的,因此
可以看出,这个概率是1/24,而这样的情况有多少种呢?
比如一个左边两个右边,就有3种情况,就是3只鸭子分别在左边;
还有就是两只鸭子在左边,一只鸭子在右边,也是3种情况,一共6种情况,总概率是6/24=0.25。
最后,加上之前三只鸭子在一边的情况,就是0.25+0.25=0.5,也得出了0.5。
不过,有人说这是初中题,初中生未必懂积分。当然,从答案反推道理也不难,这里就不推了。
感觉以后要辅导女儿搞奥数也不容易,但好歹可以省了不少培训班的钱。哎,可怜天下父母心。
根据网友回答总结了通项公式,四大不用这么复杂:
假设n只鸭子,其中一个角度是零,则有;
1.其余都大于0的概率;(1/2)^(n-1);
2.至少一个小于零,假设a1最小,那么它的范围是(-0.5,0),其余的范围只能是(a1,a1+0.5),都是0.5的区间,一共(1/2)^(n-2),再乘以a1的0.5,变成(1/2)^(n-1),一共n-1个这样的(有一个是0),因此是(n-1)(1/2)^(n-1)(
3.综合1,2,一共是n(1/2)^(n-1);
如果n=4,4*0.125=0.5,没错。
或者更容易理解的方式:假设一号鸭子最左,那么其余鸭子离他0.5的概率论是0.5^(n-1);由于每只鸭子最左的概率论是一样的,所以加起来就是n(1/2)^(n-1)