|
| 1 | +--- |
| 2 | +tags: |
| 3 | + - Original |
| 4 | +--- |
| 5 | + |
| 6 | +# Minimum Enclosing Circle |
| 7 | + |
| 8 | +Consider the following problem: |
| 9 | + |
| 10 | +!!! example "[Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle)" |
| 11 | + |
| 12 | + You're given $n \leq 10^5$ points $p_i=(x_i, y_i)$. |
| 13 | + |
| 14 | + For each $p_i$, find whether it lies on the circumference of the minimum enclosing circle of $\{p_1,\dots,p_n\}$. |
| 15 | + |
| 16 | +Here, by the minimum enclosing circle (MEC) we mean a circle with minimum possible radius that contains all the $n$ p, inside the circle or on its boundary. This problem has a simple randomized solution that, on first glance, looks like it would run in $O(n^3)$, but actually works in $O(n)$ expected time. |
| 17 | + |
| 18 | +To better understand the reasoning below, we should immediately note that the solution to the problem is unique: |
| 19 | + |
| 20 | +??? question "Why is the MEC unique?" |
| 21 | + |
| 22 | + Consider the following setup: Let $r$ be the radius of the MEC. We draw a circle of radius $r$ around each of the p $p_1,\dots,p_n$. Geometrically, the centers of circles that have radius $r$ and cover all the points $p_1,\dots,p_n$ form the intersection of all $n$ circles. |
| 23 | + |
| 24 | + Now, if the intersection is just a single point, this already proves that it is unique. Otherwise, the intersection is a shape of non-zero area, so we can reduce $r$ by a tiny bit, and still have non-empty intersection, which contradicts the assumption that $r$ was the minimum possible radius of the enclosing circle. |
| 25 | + |
| 26 | + With a similar logic, we can also show the uniqueness of the MEC if we additionally demand that it passes through a given specific point $p_i$ or two points $p_i$ and $p_j$ (it is also unique because its radius uniquely defines it). |
| 27 | + |
| 28 | + Alternatively, we can also assume that there are two MECs, and then notice that their intersection (which contains p $p_1,\dots,p_n$ already) must have a smaller diameter than initial circles, and thus can be covered with a smaller circle. |
| 29 | + |
| 30 | +## Welzl's algorithm |
| 31 | + |
| 32 | +For brevity, let's denote $\operatorname{mec}(p_1,\dots,p_n)$ to be the MEC of $\{p_1,\dots,p_n\}$, and let $P_i = \{p_1,\dots,p_i\}$. |
| 33 | + |
| 34 | +The algorithm, initially [proposed](https://doi.org/10.1007/BFb0038202) by Welzl in 1991, goes as follows: |
| 35 | + |
| 36 | +1. Apply a random permutation to the input sequence of points. |
| 37 | +2. Maintain the current candidate to be the MEC $C$, starting with $C = \operatorname{mec}(p_1, p_2)$. |
| 38 | +3. Iterate over $i=3..n$ and check if $p_i \in C$. |
| 39 | + 1. If $p_i \in C$ it means that $C$ is the MEC of $P_i$. |
| 40 | + 2. Otherwise, assign $C = \operatorname{mec}(p_i, p_1)$ and iterate over $j=2..i$ and check if $p_j \in C$. |
| 41 | + 1. If $p_j \in C$, then $C$ is the MEC of $P_j$ among circles that pass through $p_i$. |
| 42 | + 2. Otherwise, assign $C=\operatorname{mec}(p_i, p_j)$ and iterate over $k=1..j$ and check if $p_k \in C$. |
| 43 | + 1. If $p_k \in C$, then $C$ is the MEC of $P_k$ among circles that pass through $p_i$ and $p_j$. |
| 44 | + 2. Otherwise, $C=\operatorname{mec}(p_i,p_j,p_k)$ is the MEC of $P_k$ among circles that pass through $p_i$ and $p_j$. |
| 45 | + |
| 46 | +We can see that each level of nestedness here has an invariant to maintain (that $C$ is the MEC among circles that also pass through additionally given $0$, $1$ or $2$ points), and whenever the inner loop closes, its invariant becomes equivalent to the invariant of the current iteration of its parent loop. This, in turn, ensures the _correctness_ of the algorithm as a whole. |
| 47 | + |
| 48 | +Omitting some technical details, for now, the whole algorithm can be implemented in C++ as follows: |
| 49 | + |
| 50 | +```cpp |
| 51 | +struct point {...}; |
| 52 | + |
| 53 | +// Is represented by 2 or 3 points on its circumference |
| 54 | +struct mec {...}; |
| 55 | + |
| 56 | +bool inside(mec const& C, point p) { |
| 57 | + return ...; |
| 58 | +} |
| 59 | + |
| 60 | +// Choose some good generator of randomness for the shuffle |
| 61 | +mt19937_64 gen(...); |
| 62 | +mec enclosing_circle(vector<point> &p) { |
| 63 | + ranges::shuffle(p, gen); |
| 64 | + auto C = mec{p[0], p[1]}; |
| 65 | + for(int i = 0; i < n; i++) { |
| 66 | + if(!inside(C, p[i])) { |
| 67 | + C = mec{p[i], p[0]}; |
| 68 | + for(int j = 0; j < i; j++) { |
| 69 | + if(!inside(C, p[j])) { |
| 70 | + C = mec{p[i], p[j]}; |
| 71 | + for(int k = 0; k < j; k++) { |
| 72 | + if(!inside(C, p[k])) { |
| 73 | + C = mec{p[i], p[j], p[k]}; |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | + return C; |
| 81 | +} |
| 82 | +``` |
| 83 | +
|
| 84 | +Now, it is to be expected that checking that a point $p_i$ is inside the MEC of $2$ or $3$ points can be done in $O(1)$ (we will discuss this later on). But even then, the algorithm above looks as if it would take $O(n^3)$ in the worst case just because of all the nested loops. So, how come we claimed the linear expected runtime? Let's figure out! |
| 85 | +
|
| 86 | +### Complexity analysis |
| 87 | +
|
| 88 | +For the inner-most loop (over $k$), clearly its expected runtime is $O(j)$ operations. What about the loop over $j$? |
| 89 | +
|
| 90 | +It only triggers the next loop if $p_j$ is on the boundary of the MEC of $P_j$ that also passes through point $i$, _and removing $p_j$ would further shrink the circle_. Of all points in $P_j$ there can only be at most $2$ points with such property, because if there are more than $2$ points from $P_j$ on the boundary, it means that after removing any of them, there will still be at least $3$ points on the boundary, sufficient to uniquely define the circle. |
| 91 | +
|
| 92 | +In other words, after initial random shuffle, there is at most $\frac{2}{j}$ probability that we get one of the at most two unlucky points as $p_j$. Summing it up over all $j$ from $1$ to $i$, we get the expected runtime of |
| 93 | +
|
| 94 | +$$ |
| 95 | +\sum\limits_{j=1}^i \frac{2}{j} \cdot O(j) = O(i). |
| 96 | +$$ |
| 97 | +
|
| 98 | +In exactly same fashion we can now also prove that the outermost loop has expected runtime of $O(n)$. |
| 99 | +
|
| 100 | +### Checking that a point is in the MEC of 2 or 3 points |
| 101 | +
|
| 102 | +Let's now figure out the implementation detail of `point` and `mec`. In this problem, it turns out to be particularly useful to use [std::complex](https://codeforces.com/blog/entry/22175) as a class for points: |
| 103 | +
|
| 104 | +```cpp |
| 105 | +using ftype = int64_t; |
| 106 | +using point = complex<ftype>; |
| 107 | +``` |
| 108 | + |
| 109 | +As a reminder, a complex number is a number of type $x+yi$, where $i^2=-1$ and $x, y \in \mathbb R$. In C++, such complex number is represented by a 2-dimensional point $(x, y)$. Complex numbers already implement basic component-wise linear operations (addition, multiplication by a real number), but also their multiplication and division carry certain geometric meaning. |
| 110 | + |
| 111 | +Without going in too much detail, we will note the most important property for this particular task: Multiplying two complex numbers adds up their polar angles (counted from $Ox$ counter-clockwise), and taking a conjugate (i.e. changing $z=x+yi$ into $\overline{z} = x-yi$) multiplies the polar angle with $-1$. This allows us to formulate some very simple criteria for whether a point $z$ is inside the MEC of $2$ or $3$ specific points. |
| 112 | + |
| 113 | +#### MEC of 2 points |
| 114 | + |
| 115 | +For $2$ points $a$ and $b$, their MEC is simply the circle centered at $\frac{a+b}{2}$ with the radius $\frac{|a-b|}{2}$, in other words the circle that has $ab$ as a diameter. To check if $z$ is inside this circle we simply need to check that the angle between $za$ and $zb$ is not acute. |
| 116 | + |
| 117 | +<center> |
| 118 | +<img src="https://upload.wikimedia.org/wikipedia/commons/8/8e/Diameter_angles.svg"> |
| 119 | +<br> |
| 120 | +<i>Inner angles are obtuse, external angles are acute and angles on the circumference are right</i> |
| 121 | +</center> |
| 122 | + |
| 123 | +Equivalently, we need to check that |
| 124 | + |
| 125 | +$$ |
| 126 | +I_0=(b-z)\overline{(a-z)} |
| 127 | +$$ |
| 128 | + |
| 129 | +doesn't have a positive real coordinate (corresponding to points that have a polar angle between $-90^\circ$ and $90^\circ$). |
| 130 | + |
| 131 | +#### MEC of 3 points |
| 132 | + |
| 133 | +Adding $z$ to the triangle $abc$ will make it a quadrilateral. Consider the following expression: |
| 134 | + |
| 135 | +$$ |
| 136 | +\angle azb + \angle bca |
| 137 | +$$ |
| 138 | + |
| 139 | +In a [cyclic quadrilateral](https://en.wikipedia.org/wiki/Cyclic_quadrilateral), if $c$ and $z$ are from the same side of $ab$, then the angles are equal, and will ad up to $0^\circ$ when summed up signed (i.e. positive if counter-clockwise and negative if clockwise). Correspondingly, if $c$ and $z$ are on the opposite sides, the angles will add up to $180^\circ$. |
| 140 | + |
| 141 | +<center> |
| 142 | +<img src="https://upload.wikimedia.org/wikipedia/commons/3/30/Opposing_inscribed_angles.svg"> |
| 143 | +<br> |
| 144 | +<i>Adjacent inscribed angles are same, opposing angles complement to 180 degrees</i> |
| 145 | +</center> |
| 146 | + |
| 147 | +In terms of complex numbers, we can note that $\angle azb$ is the polar angle of $(b-z)\overline{(a-z)}$ and $\angle bca$ is the polar angle of $(a-c)\overline{(b-c)}$. Thus, we can conclude that $\angle azb + \angle bca$ is the polar angle of |
| 148 | + |
| 149 | +$$ |
| 150 | +I_1 = (b-z) \overline{(a-z)} (a-c) \overline{(b-c)} |
| 151 | +$$ |
| 152 | + |
| 153 | +If the angle is $0^\circ$ or $180^\circ$, it means that the imaginary part of $I_1$ is $0$, otherwise we can deduce whether $z$ is inside or outside of the enclosing circle of $abc$ by checking the sign of the imaginary part of $I_1$. Positive imaginary part corresponds to positive angles, and negative imaginary part corresponds to negative angles. |
| 154 | + |
| 155 | +But which one of them means that $z$ is inside or outside of the circle? As we already noticed, having $z$ inside the circle generally increases the magnitude of $\angle azb$, while having it outside the circle decreases it. As such, we have the following 4 cases: |
| 156 | + |
| 157 | +1. $\angle bca > 0^\circ$, $c$ on the same side of $ab$ as $z$. Then, $\angle azb < 0^\circ$, and $\angle azb + \angle bca < 0^\circ$ for points inside the circle. |
| 158 | +3. $\angle bca < 0^\circ$, $c$ on the same side of $ab$ as $z$. Then, $\angle azb > 0^\circ$, and $\angle azb + \angle bca > 0^\circ$ for points inside the circle. |
| 159 | +2. $\angle bca > 0^\circ$, $c$ on the opposite side of $ab$ to $z$. Then, $\angle azb > 0^\circ$ and $\angle azb + \angle bca > 180^\circ$ for points inside the circle. |
| 160 | +4. $\angle bca < 0^\circ$, $c$ on the opposite side of $ab$ to $z$. Then, $\angle azb < 0^\circ$ and $\angle azb + \angle bca < 180^\circ$ for points inside the circle. |
| 161 | + |
| 162 | +In other words, if $\angle bca$ is positive, points inside the circle will have $\angle azb + \angle bca < 0^\circ$, otherwise they will have $\angle azb + \angle bca > 0^\circ$, assuming that we normalize the angles between $-180^\circ$ and $180^\circ$. This, in turn, can be checked by the signs of imaginary parts of $I_2=(a-c)\overline{(b-c)}$ and $I_1 = I_0 I_2$. |
| 163 | + |
| 164 | +**Note**: As we multiply four complex numbers to get $I_1$, the intermediate coefficients can be as large as $O(A^4)$, where $A$ is the largest coordinate magnitude in the input. On the bright side, if the input is integer, both checks above can be done fully in integers. |
| 165 | + |
| 166 | +#### Implementation |
| 167 | + |
| 168 | +Now, to actually implement the check, we should first decide how to represent the MEC. As our criteria work with the points directly, a natural and efficient way to do this is to say that MEC is directly represented as a pair or triple of points that defines it: |
| 169 | + |
| 170 | +```cpp |
| 171 | +using mec = variant< |
| 172 | + array<point, 2>, |
| 173 | + array<point, 3> |
| 174 | +>; |
| 175 | +``` |
| 176 | + |
| 177 | +Now, we can use `std::visit` to efficiently deal with both cases in accordance with criteria above: |
| 178 | + |
| 179 | +```cpp |
| 180 | +/* I < 0 if z inside C, |
| 181 | + I > 0 if z outside C, |
| 182 | + I = 0 if z on the circumference of C */ |
| 183 | +ftype indicator(mec const& C, point z) { |
| 184 | + return visit([&](auto &&C) { |
| 185 | + point a = C[0], b = C[1]; |
| 186 | + point I0 = (b - z) * conj(a - z); |
| 187 | + if constexpr (size(C) == 2) { |
| 188 | + return real(I0); |
| 189 | + } else { |
| 190 | + point c = C[2]; |
| 191 | + point I2 = (a - c) * conj(b - c); |
| 192 | + point I1 = I0 * I2; |
| 193 | + return imag(I2) < 0 ? -imag(I1) : imag(I1); |
| 194 | + } |
| 195 | + }, C); |
| 196 | +} |
| 197 | + |
| 198 | +bool inside(mec const& C, point p) { |
| 199 | + return indicator(C, p) <= 0; |
| 200 | +} |
| 201 | + |
| 202 | +``` |
| 203 | +
|
| 204 | +Now, we can finally ensure that everything works by submitting the problem to the Library Checker: [#308668](https://judge.yosupo.jp/submission/308668). |
| 205 | +
|
| 206 | +## Practice problems |
| 207 | +
|
| 208 | +- [Library Checker - Minimum Enclosing Circle](https://judge.yosupo.jp/problem/minimum_enclosing_circle) |
| 209 | +- [BOI 2002 - Aliens](https://www.spoj.com/problems/ALIENS) |
0 commit comments