๐ก์ต๊ทผ์ ์ ์ ์ (Closest Pair) ๋ฌธ์ ?
- 2์ฐจ์ ํ๋ฉด์์ n๊ฐ์ ์ ์ด ์ ๋ ฅ์ผ๋ก ์ฃผ์ด์ง ๋, ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ์ฅ ๊ฐ๊น์ด ํ ์์ ์ ์ ์ฐพ๋ ๋ฌธ์
๐ก๊ฐ๋จํ ํด๊ฒฐ ๋ฐฉ๋ฒ : O(n^2) ์๊ณ ๋ฆฌ์ฆ
- ๋ชจ๋ ์ ์ ๋ํด ๊ฐ๊ฐ์ ๋์ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ์ฌ ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์ ์ ์ฐพ๊ธฐ
- ๋น๊ตํค์ผ ํ ์์ ๋ช๊ฐ?
- nC2 = n(n-1)/2 = O(n^2)
- ํ์์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ O(1)
- ๋ฐ๋ผ์ ์๊ฐ ๋ณต์ก๋๋ O(n^2)
๐ก๋ณด๋ค ํจ์จ์ ์ธ ํด๊ฒฐ๋ฐฉ๋ฒ : ๋ถํ ์ ๋ณต ์ด์ฉ
- n๊ฐ์ ์ ์ 1/2๋ก ๋ถํ ํ์ฌ ๊ฐ๊ฐ์ ๋ถ๋ถ ๋ฌธ์ ์์ ์ต๊ทผ์ ์ ์ ์ ์ฐพ๊ธฐ
- 2๊ฐ์ ๋ถ๋ถํด ์ค์์ ์งง์ ๊ฑฐ๋ฆฌ (d)๋ฅผ ๊ฐ์ง ์ ์ ์์ ์ผ๋จ ์ฐพ๊ธฐ (์ฌ๊ท์ ์ผ๋ก)
- ๊ฒฐํฉ : ๋๊ฐ์ ๋ถ๋ถํด๋ฅผ ์ทจํฉํ ๋๋ ๋ฐ๋์ ๋ ๋ถ๋ถ ๋ฌธ์ ์ ๊ฐ๊ฐ ํ ์ ์ฉ ํฌํจ๋๋ ์ ์ ์ ์ค์์ ๊ทธ ๊ฑฐ๋ฆฌ๊ฐ d๋ณด๋ค ์์ ์ ์ฐพ๊ธฐ (์ค๊ฐ ์์ญ ๊ณ ๋ ค)
- ๋ง์ฝ d๋ณด๋ค ์์ ์์ด ๋์๋ค๋ฉด, ๊ทธ๋ฐ ์ ์ค์ ๊ฐ์ฅ ์งง์ ์์ด ํด์ด๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด ๊ฑฐ๋ฆฌ๊ฐ d์ธ ์์ด ํด์ด๋ค.
์ค๊ฐ ์์ญ์ ์๋ ์๋ค์ ๊ฒ์ํ๋ ๋ฐฉ๋ฒ
- ์ ๋ค์ ์งํฉ์ S๋ผ๊ณ ํ๊ณ , S๋ฅผ ๋๋ก ๋๋ ์งํฉ์ SL, SR ์ด๋ผ๊ณ ํ์
- SL, SR์์ ๊ฐ๊ฐ ์ฐพ์ closest pair์ ๊ฐ๊ฐ CPL, CPR ์ด๋ผ๊ณ ํ๊ณ , ๋์ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ dist()ํจ์๋ก ํ์ํ๋ฉด
- d = min(dist(CPL), dist(CPR)) = min{10, 15} = 10
- ๊ทธ๋ฌ๋ฉด, ๋ถํ ํ ์ง์ ์์ X์ถ์ผ๋ก +-d (+-10) ์ธ ๋ฒ์์ ์ํ ์ ๋ค๋ง ๊ฒ์ํด๋ ์ถฉ๋ถ
- x์ขํ์ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ค์ด ์ ๋ ฌ๋์ด ์๋ค๋ฉด, ์ค๊ฐ์์ญ ๊ณผ์ ์์ ๊ฒ์ํ ์ ๋ค์ ํ์ํ ์ ์๋ค.
๐ก ์ต๊ทผ์ ์ ์ ์ ๋ถํ ์ ๋ณต ์๊ณ ๋ฆฌ์ฆ
- if (i<=3) return (2๊ฐ ๋๋ 3๊ฐ์ ์ ์ฌ์ด์ ์ต๊ทผ์ ์)
- ์ ๋ ฌ๋ S๋ฅผ ๊ฐ์ ํฌ๊ธฐ์ SL๊ณผ SR๋ก ๋ถํ
- |S|๊ฐ ํ์์ด๋ฉด, |SL| = |SR| + 1 ์ด ๋๋๋ก ๋ถํ
- CPL = ClosestPair(SL) //CPL = SL์์์ ์ต๊ทผ์ ์ ์ ์
- CPR = ClosestPair(SR) //CPR = SR์์์ ์ต๊ทผ์ ์ ์ ์
- d = min{dist(CPL), dist(CPR)} ์ผ๋, ์ค๊ฐ ์์ญ์ ์ํ๋ ์ ๋ค ์ค์์ ์ต๊ทผ์ ์ ์ ์์ ์ฐพ์์ ์ด๋ฅผ CPC๋ผ๊ณ ํ์.
- return (CPL, CPR, CPC ์ค์ ๊ฐ์ฅ ๊ฑฐ๋ฆฌ๊ฐ ์งง์ ์)
์์ ์๊ณ ๋ฆฌ์ฆ
์์ ์ฌ์ง์ ์๋ ๋ชจ๋ ์ ๋ค์ ์์ค ๊ฐ์ฅ ์ต๊ทผ์ ์ ์ ์์ ์ฐพ์๋ณด์
โ๏ธ ์ค๊ฐ์์ญ์์ CPC์ ์ฐพ์ ๋, SL๊ณผ SR์ด ๋ชจ๋ ์ค๊ฐ์์ญ์ ์์ ๊ฒฝ์ฐ? O(n^2)
- Brute forceํ ๋ฐฉ๋ฒ์ผ๋ก closest pair๋ฅผ ๊ตฌํ๋ค๋ฉด O(n^2) -> ์๋ฌด๋ฐ ์ด๋์ ๋ณผ ์ ์์
-
for(i=1;i<=n;i++){ for(j=i+1;j<=n;j++){ d(ij) = dist(pi,pj)๋ฅผ ๊ตฌํ๊ณ , d(ij)<d ์ด๋ฉด, d=d(ij) } }โ
- ์ค๊ฐ ์์ญ์ ์๋ ์ ๋ค์ y์ขํ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์ ๋๋ ๋ด๋ฆผ์ฐจ์์ผ๋ก ์ ๋ ฌํ์
- -> y ์ถ์ผ๋ก ๋ด๋ฆผ์ฐจ์์ผ๋ก ์ ๋ ฌํ ์ ๋ค์ p1, p2, ... pn์ด๋ผ๊ณ ํ์.
- ์ pi์ y์ขํ๋ฅผ yi ๋ผ๊ณ ํ์. ์ ๋ค์ด y ๋ฐฉํฅ์ผ๋ก ์ ๋ ฌ๋์ด ์์ผ๋ฏ๋ก, ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ด ๋ณด๋ค ํจ์จ์ ์ด๋ค.
-
๊ทธ๋ฌ๋, ์ ๊ณผ์ ์ d ๊ฐ์ ๋ฐ๋ผ ๊ทธ ์๋๊ฐ ๊ฒฐ์ ๋๋ค.for(i=1;i<=n-1;i++) for(j=1+1;j<=n;j++) if(yi-yj>=d) break; d(ij) = dist(pi, pj)๋ฅผ ๊ตฌํ๊ณ , d(ij)<d ์ด๋ฉด d=d(ij)
-
๐ก์คํ์ฝ๋ C++
#include <iostream>
#include <vector> // ๋ฒกํฐ ๋ฆฌ์คํธ์ ์ฌ์ฉ
#include <utility> // ์
๋ ฅ๊ฐ -> ๋ฒกํฐ๋ฆฌ์คํธ ํ์์ผ๋ก
#include <cmath> // sqrt ์ฌ์ฉ
#include <sstream> // ์
๋ ฅ๊ฐ ์ถ์ถ ์ ์ฌ์ฉ
#define X first
#define Y second
// ์
์ถ๋ ฅ ์๋ ๊ฐ์
#define IOFAST ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
vector<pair<long long, long long> > list;
// ์
๋ ฅ ์ถ์ถ ๋ฐ ๋ฌธ์์ด -> ์ซ์ ๋ณ๊ฒฝ ํจ์
void parseInt(string tmp) {
stringstream ss(tmp);
vector<long long> temp;
for (int i; ss >> i;) {
temp.push_back(i);
if (ss.peek() == ',' || ss.peek() == ' ')
ss.ignore();
}
list.push_back(make_pair(temp[0], temp[1]));
}
void quickSortX(int start, int end){
if(start >= end) return;
int key = start;
int i = start + 1, j = end;
pair<long long, long long> temp;
while (i<=j){
while(i<=end && list[i].X <= list[key].X) i++;
while(j>start && list[j].X >= list[key].X) j--;
if(i>j){
temp = list[j];
list[j] = list[key];
list[key] = temp;
} else {
temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
quickSortX(start, j-1);
quickSortX(j+1, end);
}
void quickSortY(int start, int end){
if(start >= end) return;
int key = start;
int i = start + 1, j = end;
pair<long long, long long> temp;
while (i<=j){
while(i<=end && list[i].Y <= list[key].Y) i++;
while(j>start && list[j].Y >= list[key].Y) j--;
if(i>j){
temp = list[j];
list[j] = list[key];
list[key] = temp;
} else {
temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
quickSortY(start, j-1);
quickSortY(j+1, end);
}
double Dist(pair<long long, long long> x, pair<long long, long long> y){
return sqrt((x.X-y.X) * (x.X-y.X) + (x.Y-y.Y) * (x.Y-y.Y));
}
double CPCCheck(int left, int right, double d){
quickSortY(left, right);
for(int i=left; i<=right; ++i){
for(int j=i+1; j<=right; ++j){
if(list[j].Y-list[i].Y>d) break;
double tmp = Dist(list[i], list[j]);
d = d < tmp ? d : tmp;
}
}
return d;
}
double ClosestPair(int left, int right){
int dots = right-left+1;
double min;
if(dots == 2){ // ์ ์ด ๋์ ์ผ๋ ๊ทธ๋ฅ ๊ตฌํ๋ฉด ๋จ
return Dist(list[left], list[right]);
} else if(dots == 3){ // 3์ ์ผ๋ 3์ ์ฌ์ด ๊ฑฐ๋ฆฌ
double a = Dist(list[left], list[left + 1]);
double b = Dist(list[left + 1], list[left + 2]);
double c = Dist(list[left+2],list[left]);
if(a<b){
if(a<c){
return a;
}
return c;
}
else{
if(b<c){
return b;
}
return c;
}
} else {
int mid = (left + right) / 2;
double a = ClosestPair(left, mid);
double b = ClosestPair(mid+1, right);
min = a < b ? a : b;
return CPCCheck(left, right, min);
}
}
int main() {
IOFAST;
int dots;
cin >> dots;
cin.ignore();
for(int i=0; i<dots; ++i){
string s;
// ์ค ๋ฐ๊ฟ ๊น์ง ์
๋ ฅ ๋ฐ๊ธฐ
getline(cin, s);
parseInt(s);
}
quickSortX(0, list.size());
// for ์์์ 6์๋ฆฌ ์ถ๋ ฅ
cout << fixed;
cout.precision(6);
cout << ClosestPair(0, list.size());
}
๐ก์๊ฐ ๋ณต์ก๋
์ ๋ ฅ s์ n๊ฐ์ ์ ์ด ์๋ค๋ฉด,
- ์ ์ฒ๋ฆฌ ๊ณผ์ ์ผ๋ก์ s์ ์ ์ x-์ขํ๋ก ์ ๋ ฌ : O(nlogn)
- s์ 3๊ฐ์ ์ ์ด ์๋ ๊ฒฝ์ฐ์ 3๋ฒ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ด ํ์ํ๊ณ , s์ ์ ์ ์๊ฐ 2์ด๋ฉด 1๋ฒ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ด ํ์ํ๋ฏ๋ก O(1)์ ์๊ฐ
- ์ ๋ ฌ๋ s๋ฅผ sl๊ณผ sr๋ก ๋ถํ ํ๋๋ฐ, ์ด๋ฏธ ๋ฐฐ์ด์ ์ ๋ ฌ๋์ด ์์ผ๋ฏ๋ก, ๋ฐฐ์ด์ ์ค๊ฐ ์ธ๋ฑ์ค๋ก ๋ถํ : O(1)์ ์๊ฐ
- sl๊ณผ sr์ ๋ํ์ฌ ๊ฐ๊ฐ ClosestPair์ ํธ์ถํ๋๋ฐ, ๋ถํ ํ๋ฉฐ ํธ์ถ๋๋ ๊ณผ์ ์ ํฉ๋ณ์ ๋ ฌ๊ณผ ๋์ผ
- (1) d = min{dist(cpl), dist(cpr)}์ผ ๋, ์ค๊ฐ ์์ญ์ ์ํ๋ ์ ๋ค ์ค์์ ์ต๊ทผ์ ์ ์ ์์ ์ฐพ๋๋ค.
- y ์ขํ๋ก ์ ๋ ฌํ๋ ์๊ฐ : O(nlogn)
- ๊ทธ๋ค์ ์๋์์ ์๋ก ์ฌ๋ผ๊ฐ๋ฉฐ ๊ฐ ์ ์์ ์ฃผ๋ณ์ ์ ๋ค ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๋๋ฐ O(1)์ ์๊ฐ
- ๊ฐ ์ ๊ณผ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํด์ผํ๋ ์ฃผ๋ณ ์ ๋ค์ ์๋ O(1)๊ฐ ์ด๊ธฐ ๋๋ฌธ!
- (2) cpl, cpc, cpr ์ ์ ์์ค์ ๊ฐ์ฅ ์งง์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ์ง ์ ์ ์์ ๋ฆฌํด : O(1)์ ์๊ฐ
- k์ธต๊น์ง ๋ถํ ๋ ํ, ์ธต๋ณ๋ก (1), (2) ์ด ์ํ๋๋ combine (์ทจํฉ) ๊ณผ์ ์ ์งํํ๋ฏ๋ก
- ClosestPair ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ๋ณต์ก๋ = O(nlog(^2)n)
- ๊ฐ์ธต์ y์ขํ ์ ๋ ฌ์ ์ํ์๊ฐ์ O(nlogn)
- ์ฌ๊ธฐ์ ์ธต ์์ธ logn
- ClosestPair ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ๋ณต์ก๋ = O(nlog(^2)n)
โ O(nlogn)์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๊ฐ์ ํ๊ธฐ
- ์ ๋ ฅ์ ์ ๋ค์ y ์ขํ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ์ฒ๋ฆฌ ๊ณผ์ ์์ ๋ฏธ๋ฆฌ ์ ๋ ฌํ๊ธฐ
-
double ClosestPair(int left, int right){ int dots = right-left+1; double min; if(dots == 2){ return distance(list[left], list[right]); } else if(dots == 3){ double a = distance(list[left], list[left + 1]); double b = distance(list[left + 1], list[left + 2]); return a < b ? a : b; } else { int mid = (left + right) / 2; double a = ClosestPair(left, mid); double b = ClosestPair(mid+1, right); min = a < b ? a : b; return CheckBand(left, right, min); } }
- ์ด ์ฝ๋์์ if, else if๋ฌธ์๋ ์ ๋ ฌ์ ๊ทธ๋ฅ ๋ฃ์ด์ค -> 2, 3 ๊ฐ๋๊น ๊ทธ๋ฅ O(1)์ผ๋ก ์ ๋ ฌ
- else ๋ฌธ์๋ mergesort๋ฅผ ๋ฃ์ด์ค -> ์ด๋ฏธ ์ ๋ ฌ๋ 2๊ฐ, 3๊ฐ ์ง๋ฆฌ -> O(n)
๐ก์์ฉ
- ์ปดํจํฐ ๊ทธ๋ํฝ์ค
- ์ปดํจํฐ ๋น์
- ์ง๋ฆฌ์ ๋ณด ์์คํ
- ๋ถ์ ๋ชจ๋ธ๋ง
- ํญ๊ณต ํธ๋ํฝ ์กฐ์
- ๋ง์ผํ (์ฃผ์ ์, ํ๋์ฐจ์ด์ฆ ์ ๊ท ๊ฐ๋งน์ ๋ฑ์ ์์น ์ ์ ๋ฑ)
Reference
์์ธ๊ณผํ๊ธฐ์ ๋ํ๊ต ์ปดํจํฐ๊ณตํ๊ณผ ์๊ณ ๋ฆฌ์ฆ ์์
'Algorithm' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Algorithm] ์ต๋จ ๊ฒฝ๋ก ์ฐพ๊ธฐ : ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ (0) | 2021.10.11 |
---|---|
[Algorithm] ์ต์ ์ ์ฅ ํธ๋ฆฌ : ํฌ๋ฃจ์ค์ปฌ & ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ (0) | 2021.10.11 |
[Algorithm] ๊ทธ๋ฆฌ๋(Greedy) ์๊ณ ๋ฆฌ์ฆ (0) | 2021.10.06 |
[Algorithm] ๋ถํ ์ ๋ณต ์๊ณ ๋ฆฌ์ฆ (0) | 2021.10.06 |
[Algorithm] ์ ํ๋ฌธ์ ์๊ณ ๋ฆฌ์ฆ (feat. Quick-Sort) (0) | 2021.09.29 |