题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=4739
http://uoj.ac/problem/277
不难得出一个结论: 两圆之间最短路一定沿着圆的公切线走。然后得到如下算法:每两个圆之间作公切线(4条),如果一条公切线不穿过其他圆,就把这两个点(图论中的点)之间连上边,边权为切线长;同一圆上相邻两点连边,边权为圆上距离,然后S,T分别向每个圆作切线如果不和其他圆相交就连边。这样的话点数、边数是 O ( n 2 ) O(n^2) O(n2)级别的,使用Dijkstra算法求最短路即可。时间复杂度瓶颈在于对于一条边枚举每一个圆去check是否相交,总时间复杂度 O ( n 3 ) O(n^3) O(n3). 奇迹般地能跑过。
下面重点讲解一下我是如何求两圆公切线以及点和圆的切线的:
先来说两圆公切线:因为两圆外离所以一定有 4 4 4条公切线, 2 2 2内 2 2 2外。
考虑先把圆按半径从大到小排序,现在要从半径大的圆向半径小的圆作 4 4 4条切线。
设两圆圆心(已知)分别为 O 1 , O 2 O_1, O_2 O1,O2, 圆心的直线距离 O 1 O 2 = d O_1O_2=d O1O2=d, 半径分别为 r 1 r 2 r_1r_2 r1r2, 一条外公切线为 A B AB AB(未知)。
过 O 2 O_2 O2作 O 2 E ⊥ A O 1 O_2E\perp AO_1 O2E⊥AO1于 D D D, 则 A E O 2 B AEO_2B AEO2B为矩形。 A E = B O 2 = r 2 AE=BO_2=r_2 AE=BO2=r2, E O 1 = A O 1 − A E = r 1 − r 2 EO_1=AO_1-AE=r_1-r_2 EO1=AO1−AE=r1−r2, 又 O 1 E ⊥ O 2 E O_1E\perp O_2E O1E⊥O2E, 可用勾股定理算出切线长 A B = E O 2 = d 2 − ( r 1 − r 2 ) 2 AB=EO_2=\sqrt{d^2-(r_1-r_2)^2} AB=EO2=d2−(r1−r2)2. 同时有 cos ∠ E O 1 O 2 = r 1 − r 2 d \cos \angle EO_1O_2=\frac{r_1-r_2}{d} cos∠EO1O2=dr1−r2, 可利用acos
函数算出 ∠ E O 1 O 2 \angle EO_1O_2 ∠EO1O2的值。然后求出向量 O A ⃗ =