2020-1ν•™κΈ°, λŒ€ν•™μ—μ„œ β€˜μ•Œκ³ λ¦¬μ¦˜β€™ μˆ˜μ—…μ„ λ“£κ³  κ³΅λΆ€ν•œ λ°”λ₯Ό μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€. 지적은 μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€ :) 전체 ν¬μŠ€νŠΈλŠ” Algorithm ν¬μŠ€νŠΈμ—μ„œ ν™•μΈν•˜μ‹€ 수 μžˆμŠ΅λ‹ˆλ‹€.

6 minute read

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>λ₯Ό λ§ˆμ§€λ§‰μœΌλ‘œ μ •κ·œ μˆ˜μ—…μ—μ„œ 닀룬 λͺ¨λ“  λΆ„ν•  μ •λ³΅μ˜ λ¬Έμ œλ“€μ„ μ‚΄νŽ΄λ³΄μ•˜λ‹€ πŸ‘

Categories:

Updated: