Closest pair of points
2020-1ํ๊ธฐ, ๋ํ์์ โ์๊ณ ๋ฆฌ์ฆโ ์์ ์ ๋ฃ๊ณ ๊ณต๋ถํ ๋ฐ๋ฅผ ์ ๋ฆฌํ ๊ธ์ ๋๋ค. ์ง์ ์ ์ธ์ ๋ ํ์์ ๋๋ค :)
๋ฐฑ์ค 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>๋ฅผ ๋ง์ง๋ง์ผ๋ก ์ ๊ท ์์ ์์ ๋ค๋ฃฌ ๋ชจ๋ ๋ถํ ์ ๋ณต์ ๋ฌธ์ ๋ค์ ์ดํด๋ณด์๋ค ๐