Closest pair of points
2020-1νκΈ°, λνμμ βμκ³ λ¦¬μ¦β μμ μ λ£κ³ 곡λΆν λ°λ₯Ό μ 리ν κΈμ λλ€. μ§μ μ μΈμ λ νμμ λλ€ :) μ 체 ν¬μ€νΈλ Algorithm ν¬μ€νΈμμ νμΈνμ€ μ μμ΅λλ€.
λ°±μ€ 2261λ²: κ°μ₯ κ°κΉμ΄ λ μ λ¬Έμ λ₯Ό κΈ°μ€μΌλ‘ μμ±λ ν¬μ€νΈμ λλ€.

<closest pair of points> λ¬Έμ λ $n$κ°μ μ μ΄ μλ νλ©΄μμ κ°μ₯ κ°κΉμ΄ μ ν΄λ¦¬λ 거리λ₯Ό μ°Ύλ μκ³ λ¦¬μ¦μ΄λ€. μ΄ λ¬Έμ λ 곡ν κ΄μ νμμ λ λΉνκΈ°κ° μΆ©λν μ§λ₯Ό νμΈνκ³ μλμΌλ‘ μλ €μ£Όλ μμ€ν λ±μμ λΉ λ₯΄κ² 경보λ₯Ό μΈλ¦¬κΈ° μν΄ νμν μκ³ λ¦¬μ¦μ΄λ€.
Brute Force νκ² μ κ·Όνλ€λ©΄ λͺ¨λ λ μ μ μμ λν΄ κ±°λ¦¬λ₯Ό κ΅¬ν΄ μ΅μ 거리λ₯Ό μ°Ύμ μ μλ€. κ·Έλ¬λ μ΄ λ°©λ²μ $O(n^2)$μ λΉμ©μ νμλ‘ νλ€. μ°λ¦¬λ Divide and Conquerλ‘ μ κ·Όν΄ $O(n \log n)$μ λΉμ©μΌλ‘ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν κ²μ΄λ€! π
1. Sort points in $P$ by $x$-coordinates: $P_x$. And calculate $x$-median $x_{\text{mid}}$

2. Divide the point set $P$ into two equal-sized subsets $P^{L}$ and $P^{R}$ along $x_{\text{mid}}$. And then solve the problem(= find the closest pair in subsets) for two subsets respectively.
3. Choose the minimum of the tow smallest distances, returned from each subproblem: denote it as $\delta$.
4. μλμμ κ³μβ¦
delta $\delta$λ₯Ό ꡬνλ€λ©΄, μ΄μ λ $P^L$, $P^R$μ κ±Έμ³μ μ‘΄μ¬νλ 거리λ€μ μ΄ν΄λ΄μΌ νλ€. μ΄λ $x_{\text{mid}}$μμ μ’μ°λ‘ $\delta$ λ§νΌμ 거리μ μλ μ λ€μ μ΄ν΄λ³΄λ©΄ λλ€. $2\delta$ κΈΈμ΄ λ§νΌμ νμ λ μ μνλ μ λ€μ $O(n)$μ λΉμ©μΌλ‘ μ½κ² ꡬν μ μλ€. νμ λ μ μνλ μ λ€μ λͺ¨λ ꡬνλ€λ©΄ μ΄λ²μλ $y$-coordinateλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬ν $P_y$λ₯Ό μ λνλ€.

νμ λ λ΄λΆλ₯Ό $\delta/2$ κΈΈμ΄ λ§νΌμ cellλ‘ λΆν νμ. κ·Έλ¦¬κ³ $s_i$λ₯Ό $P_y$μμ $i$λ²μ§Έλ‘ μμ $y$ μ’νλ₯Ό κ°λ μ μ΄λΌκ³ νμ. κ·Έλ¬λ©΄ μλμ νμ λ μ cellμ λν΄ μλ λ¬Έμ₯μ΄ μ±λ¦½νλ€!
- No two points lie in same $\delta/2 \times \delta/2$ box.
- λ§μ½ κ·Έλ° μ μ΄ μ‘΄μ¬νλ€λ©΄ subproblemμ ν΄κ²°νλ κ³Όμ μμ $\le \delta/2$κ° μ΅μ κ±°λ¦¬λ‘ λ½νμ΄μΌ νλ€.
- Two points at least 2 rows apart have distance $\ge \delta$.
- λΉμ°!
- If $\left| i - j \right| \ge 12$, then the distance between $s_i$ and $s_j$ is at least $\delta$.
- μ΄κ²μ 1, 2λ²μ§Έ λ¬Έμ₯μΌλ‘ μ λλλ κ±΄λ° $i$λ₯Ό κΈ°μ€μΌλ‘ 12κ°μ cellμ μ§λλ©΄ κΈΈμ΄κ° 무쑰건 $\delta$λ³΄λ€ μ»€μ§λ€λ λ§μ΄λ€.
μμ λ¬Έμ₯λ€, νΉν 3λ² λ¬Έμ₯μΌλ‘ μΈν΄ μ°λ¦¬λ $P_y$μ μν κ° μ $s_i$μ λν΄ $s_{i+1}$λΆν° $s_{i+11}$κΉμ§ λλ 2μ€ forλ¬Έμ λλ©΄ νμ λ μμ μ 체 μ μμ νμΈν νμ μμ΄ $O(12 n)$μ λΉμ©μΌλ‘ smallest distanceλ₯Ό μ°Ύμ μ μλ€!
μκ° λ³΅μ‘λλ₯Ό λΆμν΄λ³΄λ©΄
- μ μΌ μ²μμ λ€μΈ point sort: $O(n \log n)$
- λΆν μ 볡: $T(n) \le 2 T(n/2) + O(n) \implies T(n) = O(n \log n)$
λ‘ $O(n \log n)$μ λΉμ©μΌλ‘ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€!!
Code Implementation
μκ³ λ¦¬μ¦μ΄ 볡μ‘νκΈ° λλ¬Έμ μ½λλ μ‘°κΈ λ³΅μ‘νλ€.
#define Point pair<int, int>
#define point_vec vector<Point>
point_vec points;
long long dist(Point p1, Point p2){
return (p1.first - p2.first)*(p1.first - p2.first) + (p1.second - p2.second)*(p1.second - p2.second);
}
μ½λ μμ±μ νΈμλ₯Ό μν΄ Point
μ point_vec
νμ
μ μ μΈνκ³ , ν¬μΈνΈ 거리 ν¨μ dist
λ₯Ό μ μνλ€. μ κ³±κ·ΌκΉμ§ ꡬν νμλ μλ€.
// μ½μ μ
λ ₯
...
sort(points.begin(), points.end());
printf("%lld", ClosestPair(points));
κ°μ μ λ ₯ λ°μ νμλ $x$κ°μ λ°λΌ point λ°°μ΄μ μ λ ¬νλ€.
long long ClosestPair(point_vec Px){
// base case
if(Px.size() == 2)
return dist(Px[0], Px[1]);
if(Px.size() == 3)
return min({dist(Px[0], Px[1]), dist(Px[0], Px[2]), dist(Px[1], Px[2])});
int N = Px.size();
/* divide */
int mid = N / 2;
/* Px_L, Px_R */
point_vec Px_L = point_vec(Px.begin(), Px.begin() + mid);
point_vec Px_R = point_vec(Px.begin() + mid, Px.end());
long long d1 = ClosestPair(Px_L);
long long d2 = ClosestPair(Px_R);
long long d = min(d1, d2);
....
}
λͺκ°μ§ λ² μ΄μ€ μΌμ΄μ€λ€μ μ²λ¦¬νκ³ , ν¬μΈνΈ μ§ν© $P_x$λ₯Ό λΆν νμ¬ λ¬Έμ λ₯Ό ν΄κ²°νλ€. κ°κ°μμ μ»μ d1
, d2
μμμ μ΅μκ°μ d
μ μ μ₯νλ€.
/* merge */
Point point_mid = Px[mid];
point_vec Sy;
long long sqrt_d = sqrt(d);
for(int i = mid; i >= 0; i--){
if(abs(point_mid.first - Px[i].first) <= sqrt_d)
Sy.push_back(Px[i]);
else
break;
}
for(int i = mid + 1; i < N; i++){
if(abs(point_mid.first - Px[i].first) <= sqrt_d)
Sy.push_back(Px[i]);
else
break;
}
λ€μμ κ°μ΄λ°μ νμ λ μ μνλ μ λ€ $S_y$ μ°Ύλ μμ μ΄λ€. $O(n)$μ λΉμ©μ΄ λ λ€.
bool yComparator(Point p1, Point p2){
return p1.second < p2.second;
}
...
/* sort points in increasing y coordinate */
sort(Sy.begin(), Sy.end(), yComparator);
int CrossN = Sy.size();
for(int i = 0; i < CrossN; i++){
for(int j = i + 1; j < min(CrossN, i + 12); j++){
d = min(d, dist(Sy[i], Sy[j]));
}
}
return d;
$S_y$μ μ λ€μ $y$-μ’νλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬νλ€. κ·Έλ₯ μ λ ¬νκ² λλ©΄ $x$-μ’νλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬νκ² λλ―λ‘ Comparatorλ₯Ό μ μν΄μ μΈμλ‘ λ£μ΄μ€λ€. κ·Έ νμλ $S_y$μ μνλ μ λ€μ μννλ©° λ€μ 12κ°μ μ λ€κ³Όμ 거리λ₯Ό μ°λ€. $O(n * 12)$μ λΉμ©μ΄ λ λ€.
<closest pair of points>λ₯Ό λ§μ§λ§μΌλ‘ μ κ· μμ μμ λ€λ£¬ λͺ¨λ λΆν μ 볡μ λ¬Έμ λ€μ μ΄ν΄λ³΄μλ€ π