Use this to learn the idea, then write your own version.
1from dataclasses import dataclass2 3 4@dataclass(frozen=True)5class Point:6 x: float7 y: float8 9 10@dataclass(frozen=True)11class Disk:12 center: Point13 radius: float14 15 16class Solution:17 def outerTrees(self, trees: list[list[int]]) -> list[float]:18 points = [Point(x, y) for x, y in trees]19 disk = self._welzl(points, 0, [])20 return [disk.center.x, disk.center.y, disk.radius]21 22 def _welzl(23 self,24 points: list[Point],25 i: int,26 planePoints: list[Point],27 ) -> Disk:28 """Returns the smallest disk that encloses points[i..n).29 30 https:en.wikipedia.org/wiki/Smallest-disk_problem31 """32 if i == len(points) or len(planePoints) == 3:33 return self._trivial(planePoints)34 disk = self._welzl(points, i + 1, planePoints)35 if self._inside(disk, points[i]):36 return disk37 return self._welzl(points, i + 1, planePoints + [points[i]])38 39 def _trivial(self, planePoints: list[Point]) -> Disk:40 """Returns the smallest disk that encloses `planePoints`."""41 if len(planePoints) == 0:42 return Disk(Point(0, 0), 0)43 if len(planePoints) == 1:44 return Disk(Point(planePoints[0].x, planePoints[0].y), 0)45 if len(planePoints) == 2:46 return self._getDisk(planePoints[0], planePoints[1])47 48 disk01 = self._getDisk(planePoints[0], planePoints[1])49 if self._inside(disk01, planePoints[2]):50 return disk0151 52 disk02 = self._getDisk(planePoints[0], planePoints[2])53 if self._inside(disk02, planePoints[1]):54 return disk0255 56 disk12 = self._getDisk(planePoints[1], planePoints[2])57 if self._inside(disk12, planePoints[0]):58 return disk1259 60 return self._getDiskFromThree(61 planePoints[0],62 planePoints[1],63 planePoints[2])64 65 def _getDisk(self, A: Point, B: Point) -> Disk:66 """Returns the smallest disk that encloses the points A and B."""67 x = (A.x + B.x) / 268 y = (A.y + B.y) / 269 return Disk(Point(x, y), self._distance(A, B) / 2)70 71 def _getDiskFromThree(self, A: Point, B: Point, C: Point) -> Disk:72 """Returns the smallest disk that encloses the points A, B, and C."""73 74 mAB = Point((A.x + B.x) / 2, (A.y + B.y) / 2)75 mBC = Point((B.x + C.x) / 2, (B.y + C.y) / 2)76 77 78 slopeAB = math.inf if B.x == A.x else (B.y - A.y) / (B.x - A.x)79 slopeBC = math.inf if C.x == B.x else (C.y - B.y) / (C.x - B.x)80 perpSlopeAB = math.inf if slopeAB == 0 else -1 / slopeAB81 perpSlopeBC = math.inf if slopeBC == 0 else -1 / slopeBC82 83 84 x = (perpSlopeBC * mBC.x - perpSlopeAB * mAB.x +85 mAB.y - mBC.y) / (perpSlopeBC - perpSlopeAB)86 y = perpSlopeAB * (x - mAB.x) + mAB.y87 center = Point(x, y)88 return Disk(center, self._distance(center, A))89 90 def _inside(self, disk: Disk, point: Point) -> bool:91 """Returns True if the point is inside the disk."""92 return disk.radius > 0 and self._distance(disk.center, point) <= disk.radius93 94 def _distance(self, A: Point, B: Point) -> float:95 dx = A.x - B.x96 dy = A.y - B.y97 return math.sqrt(dx**2 + dy**2)98