727. 圆弧三角形(Triangle of Circular Arcs)

三个半径为\(r_a,r_b\)\(r_c\)的圆两两外切,在切点之间构成了一个圆弧三角形,如下图的三个蓝色圆所示:

记圆弧三角形的外接圆为上图中的红色圆,圆心为\(D\)且过三个切点。再记圆弧三角形的内切圆为上图中的绿色圆,圆心点为\(E\)且与三个蓝色圆外切。记\(d=|DE|\)为外接圆和内切圆的圆心距。若\(r_a,r_b,r_c\)均为在\(1\leq r_a<r_b<r_c \le 100\)范围内随机均匀抽取的整数且满足\(\text{gcd}(r_a,r_b,r_c)=1\),记\(\mathbb{E}(d)\)\(d\)的期望值,求\(\mathbb{E}(d)\)并保留小数点后八位数字。

分析:据题意我们要求\(D,E\)两点间的期望距离,而这个距离是随着半径\(r_a,r_b,r_c\)的变化而变化的。使用解析几何的思路,如果我们可以求得\(D,E\)两点的坐标,得到两点坐标和三个半径之间的关系,我们就可以知道三个半径是如何影响\(D,E\)两点间的距离的,也就不难求出期望距离。所以我们首先还是建立一个直角坐标系,为方便起见,设其原点为\(B\)点且以\(BC\)所在直线为横轴,图示如下:

据题意三个圆分别相切于点\(F,G,H\),则过三个点作圆实际上就是三角形\(\triangle ABC\)的内切圆,而\(D\)点即为\(\triangle ABC\)的内心,在已知\(A,B,C\)三点坐标的情况下,我们可以使用公式求得内心的坐标,易知\(B\)点坐标为\((0,0)\)\(C\)点坐标为\((r_b+r_c,0)\),设\(A\)点坐标为\((x_a,y_a)\),则内心\(D\)点的坐标为:

$$ x_{d} =\frac{( r_{b} +r_{c}) x_{a} +( r_{a} +r_{c})( r_{b} +r_{c})}{2( a+b+c)} ,\ y_{d} =\frac{( r_{b} +r_{c}) y_{a}}{2( a+b+c)} $$

接下来的问题是我们如何求得\(A\)点的坐标,下一节解决这个问题。

一、求解\(D\)点坐标

如上图所示,假如已经给定了\(B,C\)两个圆以及圆\(A\)的半径,我们如何求得圆\(A\)的圆心位置。想像一下,我们需要不断的移动圆\(A\)直到它和圆\(B,C\)都相切,此时圆心的位置也可以确定下来了,如下图所示:

我们要求点\(C\)的横纵坐标,设其为\((x,y)\),则我们有\(y^2=AC^2-AD^2=CB^2-BD^2\),则有:

$$ ( a+c)^{2} -x^{2} =( c+b)^{2} -( a+b-x)^{2} \Rightarrow x=\frac{( a+b)^{2} +( c+a)^{2} -( c+b)^{2}}{2( a+b)} $$

据此我们可以求出第三圆圆心的横纵坐标。使用这种方法,我们可以基于了\(B,C\)两个圆的半径与圆心位置以及圆\(A\)的半径,求解出圆\(A\)的的圆心位置,这样\(A,B,C\)三点的坐标就都知道了,我们可以据此求解三角形\(\triangle ABC\)的内心也就是\(D\)点的坐标。

二、求解\(E\)点坐标

考虑到圆\(E\)也和圆\(B\)和圆\(C\)相切,则根据前面介绍的方法,为求解\(E\)点坐标,我们只需要知道圆\(E\)的半径就可以了,而这可以使用笛卡尔定理求得。笛卡尔定理描述了四个相切圆的半径之间需满足的关系,一般地,如果给定三个相切的圆(如题目中给出的),则可以找到两个圆和这三个圆都相切,其中一个小圆位于三个圆之间(如题目中给出的情况),一个大圆则在外侧包含住三个圆并相切,如下图所示,我们这里只关心小圆的情况:

维基上的笛卡尔定理使用了曲率来描述四个圆之间的半径关系,因为对于圆来说,曲率等于其半径的倒数,因此我们可以进一步改写得到四个圆半径间的关系,假设已知三个圆的半径分别为\(r_1,r_2,r_3\),则从内部相切的第四个小圆的半径\(r_4\)为:

$$ r_{4} =\frac{r_{1} r_{2} r_{3}}{r_{1} r_{2} +r_{1} r_{3} +r_{2} r_{3} +2\sqrt{r_{1} r_{2} r_{3}( r_{1} +r_{2} +r_{3})}} $$

在已知\(r_4\)的情况下,我们可以使用前节介绍的方法进一步求解小圆的圆心坐标,从而锁定它的位置。已知\(D,E\)两点坐标,我们可以很容易知道他们之间的距离。

三、两点间的期望距离

题目要求三个半径均为\([1,100]\)间的整数且三个半径必须互质,使用\(itertools\)模块中的\(combinations\)函数,我们可以筛选出这样的三元组共有135739个,对于其中每一个,我们使用上面的方法求解\(D,E\)两点间距离,最后把所有距离加总再除以135739,即为我们要求的期望距离。代码如下:

# time cost = 764 ms ± 12.5 ms

from math import sqrt,gcd
from itertools import combinations
from functools import reduce

def cods(a,b,r):
    x = ((a+b)**2+(r+a)**2-(r+b)**2)/(2*a+2*b)
    y = sqrt((a+r)**2-x**2)
    return x,y

def inner_point(a,b,c):
    xa,ya = 0,0
    xb,yb = a+b,0
    xc,yc = cods(a,b,c)
    x = ((b+c)*xa+(a+c)*xb+(a+b)*xc)/(2*(a+b+c))
    y = ((b+c)*ya+(a+c)*yb+(a+b)*yc)/(2*(a+b+c))
    return x,y

def soddy_circle_radius(a,b,c):
    return (a*b*c)/(a*b+a*c+b*c+2*sqrt(a*b*c*(a+b+c)))

def dist(a,b,c):
    xd,yd = inner_point(a,b,c)
    xe,ye = cods(a,b,soddy_circle_radius(a,b,c))
    return sqrt((xd-xe)**2+(yd-ye)**2)

def ggcd(numbers):
    return reduce(gcd,numbers)

def main():
    res = [x for x in combinations(range(1,101),3) if ggcd(x)==1]
    return sum(dist(*x) for x in res)/len(res)

四、参考

  1. https://mathworld.wolfram.com/SoddyCircles.html
  2. https://en.wikipedia.org/wiki/Incenter#Cartesian_coordinates
  3. https://brilliant.org/wiki/descartes-theorem/
  4. https://en.wikipedia.org/wiki/Descartes%27_theorem