DevLog πŸ“¨/Baekjoon

[DevLog][Baekjoon] 2261: κ°€μž₯ κ°€κΉŒμš΄ 두 점

cece00 2023. 8. 14. 22:21

01) 문제

2차원 평면상에 n개의 점이 μ£Όμ–΄μ‘Œμ„ λ•Œ, 이 점듀 쀑 κ°€μž₯ κ°€κΉŒμš΄ 두 점을 κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€. 첫째 쀄에 μžμ—°μˆ˜ n(2 ≀ n ≀ 100,000)이 주어진닀. λ‹€μŒ n개의 μ€„μ—λŠ” μ°¨λ‘€λ‘œ 각 점의 x, yμ’Œν‘œκ°€ 주어진닀. 각각의 μ’Œν‘œλŠ” μ ˆλŒ“κ°’μ΄ 10,000을 λ„˜μ§€ μ•ŠλŠ” μ •μˆ˜μ΄λ‹€. μ—¬λŸ¬ 점이 같은 μ’Œν‘œλ₯Ό κ°€μ§ˆ μˆ˜λ„ μžˆλ‹€.

예제 μž…/좜λ ₯

4
0 0
10 10
0 10
10 0
# output is 100

02) 풀이

  1. 평면을 λΆ„ν• ν•œλ‹€
  2. λΆ„ν• λœ ν‰λ©΄μ—μ„œ μ΅œμ†Œ 거리λ₯Ό μ°ΎλŠ”λ‹€
  3. μ„œλ‘œ λΆ„ν• λ˜μ–΄ μžˆλŠ” 점듀 μ€‘μ—μ„œ μ΅œμ†Œ 거리가 될 수 μžˆλŠ” μ λ“€λ§Œ νƒμƒ‰ν•˜μ—¬ μ΅œμ†Œ 거리λ₯Ό κ°±μ‹ ν•œλ‹€.

이전 μ•Œκ³ λ¦¬μ¦˜ μˆ˜μ—…μ—μ„œ λΆ„λͺ…νžˆ μ ‘ν–ˆλ˜ λ¬Έμ œμΈλ°λ„ λ°”λ‘œ κ΅¬ν˜„μ΄ λ– μ˜€λ₯΄μ§€ μ•Šμ•˜λ‹€. μœ„μ™€ 같은 νλ¦„μœΌλ‘œ divide/combine ν•˜λ©΄ λ˜κ² κ΅¬λ‚˜ ν•˜λŠ” 생각은 λ“€μ—ˆμ§€λ§Œ, 3번 combine 단계λ₯Ό μ–΄λ–»κ²Œ κ΅¬ν˜„ν•  수 μžˆμ„μ§€ 고민이 λ˜μ—ˆλ‹€. (μ΄λž˜μ„œ 기얡에 μ˜μ‘΄ν•΄ ν’€λ©΄ μ•ˆ λœλ‹€.)

μ²˜μŒμ—λŠ” left와 rightμ—μ„œ 각각 yμ’Œν‘œμ˜ μ ˆλŒ“κ°’μ΄ κ°€μž₯ μž‘μ€ 두 점 a, bλ₯Ό 선택해, 이의 x값을 κΈ°μ€€μœΌλ‘œ 사이에 μžˆλŠ” 점만 νƒμƒ‰ν•˜λ©΄ μ–΄λ–¨κΉŒ? ν•˜λŠ” 생각이 λ“€μ—ˆλ‹€. λ‹Ήμ—°νžˆ ν‹€λ Έλ‹€. μ•„λž˜μ™€ 같은 λ°˜λ‘€κ°€ μ‘΄μž¬ν•œλ‹€.

κ²°κ΅­ ꡐ재λ₯Ό 보고, combine의 접근법을 μ•Œκ²Œ λ˜μ—ˆλ‹€. μ΅œμ†Œ 거리λ₯Ό 찾은 ν›„, mid의 xμ’Œν‘œλ₯Ό κΈ°μ€€μœΌλ‘œ xμ’Œν‘œκ°€ +/-d 인 κ²½μš°μ—λ§Œ κ²€μƒ‰μ˜ λ²”μœ„κ°€ λœλ‹€. λ§Œμ•½ xμ’Œν‘œκ°€ κ²½κ³„μ„ μ—μ„œ 이미 μ΅œμ†Œκ±°λ¦¬ dλ₯Ό μ΄ˆκ³Όν•˜μ—¬ λ–¨μ–΄μ Έ μžˆλ‹€λ©΄ μ–΄λ–€ κ²½μš°μ—λ„ λ‹€λ₯Έ μͺ½μ— μžˆλŠ” 점과 μ΅œμ†Œκ±°λ¦¬λ₯Ό 이룰 수 μ—†λ‹€.


<κ·Έλ¦Ό 1>의 L, Rμ—μ„œ μ΅œμ†Œ 거리λ₯Ό 각각 찾은 ν›„, 이λ₯Ό d = min(dL, dR) 라고 ν•œλ‹€. 쀑간에 μžˆλŠ” 점의 λ²”μœ„λŠ” κ·Έλ¦Όκ³Ό 같이 M이 λœλ‹€. 이 쀑간 μ˜μ—­μ˜ 점듀은 이쀑 λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜μ—¬ μ΅œλ‹¨κ±°λ¦¬λ₯Ό 계산해보고, μ΅œμ†Ÿκ°’μ„ μ°Ύμ•„ κ°±μ‹ ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.
이 λ•Œ, λ§Œμ•½ 쀑간 μ˜μ—­μ˜ 점듀이 yμ’Œν‘œλ₯Ό κΈ°μ€€μœΌλ‘œ μ •λ ¬λ˜μ–΄ μžˆλ‹€λ©΄, 검색 μ‹œκ°„μ„ 쀄일 수 μžˆλ‹€. (μ •ν™•νžˆλŠ” 검색이 ν•„μš” μ—†λŠ” 경우λ₯Ό μ²˜λ¦¬ν•΄μ€„ 수 μžˆλ‹€.) λ§Œμ•½ i점과 j점의 yμ’Œν‘œ Yi, Yj의 μ°¨κ°€ ν˜„μž¬κΉŒμ§€ κ°±μ‹ λœ μ΅œμ†Œκ±°λ¦¬ d보닀 큰 경우, Xi, Xj의 값에 상관없이 두 점의 κ±°λ¦¬λŠ” 항상 d보닀 ν¬κ±°λ‚˜ κ°™κ²Œ λœλ‹€.
$\ distance = \sqrt{(X_i - X_j)^2 + (Y_i - Y_j)^2} $

λ”°λΌμ„œ λ‹€μŒκ³Ό 같은 방법을 μ μš©ν•  수 μžˆλ‹€.

for i in 0 to n-1:
  for j in i+1 to n:
    if j.y - i.y >= minD:
      break
    else minD = min(minD, distance(i, j)) # update

μ‹œν–‰μ°©μ˜€: λ‚΄μž₯ν•¨μˆ˜μ˜ μ‚¬μš© μ‹œ 주의 🚨

μœ„μ™€ 같이 μ½”λ“œλ₯Ό μž‘μ„±ν–ˆλŠ”λ°, μ΄λ²ˆμ—” 'μ‹œκ°„ 초과'κ°€ 뜨고 λ§μ•˜λ‹€. 쀑간 μ˜μ—­μ˜ λ²”μœ„ 인덱슀λ₯Ό κ΅¬ν•˜λŠ” κ³Όμ •μ—μ„œ yμ’Œν‘œλ₯Ό κΈ°μ€€μœΌλ‘œ λ‚΄λ¦Όμ°¨μˆœ 정렬을 ν•˜κ³  μ‹Άμ—ˆλ‚˜λ³΄λ‹€. sort(key, reversed=True) λ₯Ό μ„€μ •ν•˜λŠ” λ°”λžŒμ— μ–΄μ΄μ—†κ²Œλ„ μ‹œκ°„ 리밋을 λ„˜μ–΄λ²„λ Έλ‹€. λ¨Έλ¦Ώμ†μ—μ„œ μƒκ°ν•œ 과정을 아무 생각 없이 μ½”λ“œλ‘œ μž‘μ„±ν–ˆκΈ°μ—, ꡳ이 ν•„μš”λ„ μ—†λŠ” μ—­μ •λ ¬ μ˜΅μ…˜μ„ κ±Έμ–΄ μ€€ 것이닀. 또, 정렬을 μ—­λ°©ν–₯으둜 ν•˜λŠ” 것이 더 였래 걸릴 κ²ƒμ΄λΌλŠ” 생각을 ν•˜μ§€ λͺ»ν–ˆλŠ”데, μ‹€μ œλ‘œλŠ” reversed=True μ˜΅μ…˜μ΄ 인풋이 μ»€μ§€λŠ” 경우 μ„±λŠ₯에 영ν–₯을 쀄 수 μžˆλ‹€κ³  ν•œλ‹€. μ‹œκ°„ λ˜λŠ” λ©”λͺ¨λ¦¬ 초과의 순기λŠ₯은 ν‰μ†Œμ— 아무 생각 없이 μ“°λ˜ λ‚΄μž₯ν•¨μˆ˜μ˜ μž‘λ™ 방식에 λŒ€ν•΄ μ‘°κΈˆμ΄λ‚˜λ§ˆ 관심을 κ°–κ³  μ°Ύμ•„λ³΄κ²Œ λ§Œλ“ λ‹€λŠ” 점인 것 κ°™λ‹€.

03) μ½”λ“œ (파이썬)

# Closest Pair
import sys
import math


def distance(d1: tuple, d2: tuple):  # 거리 제곱
    return (d1[0]-d2[0])**2 + (d1[1]-d2[1])**2


def closest_pair(s, e):
    global minD
    if e - s == 1:
        return
    if e - s == 2:
        d = distance(D[s], D[e-1])
        if minD == None or minD > d:
            minD = d
        return

    # xμ’Œν‘œμ˜ midκ°’ κ΅¬ν•˜κΈ°
    mid = (s + e) // 2

    closest_pair(s, mid)
    closest_pair(mid, e)
    d = minD

    # mid-d < x < mid+d 점 (쀑간 μ˜μ—­) 쑰사
    for i in range(mid, s-1, -1):
        if D[mid][0] - D[i][0] > math.sqrt(d):
            break
    for j in range(mid, e):
        if D[j][0] - D[mid][0] > math.sqrt(d):
            break

    # i~j 쀑간 μ˜μ—­μ—μ„œμ˜ μ΅œκ·Όμ ‘μ  쑰사
    mids = sorted(D[i:j+1], key=lambda d: d[1])
    for p in range(len(mids)-1):
        for q in range(p+1, len(mids)):
            if mids[q][1] - mids[p][1] >= math.sqrt(d):
                break
            minD = min(minD, distance(mids[q], mids[p]))

    return


# μž…λ ₯을 λ°›μŒ
N = int(input())
D = [tuple(map(int, sys.stdin.readline().split())) for _ in range(N)]
minD = None

# Dλ°°μ—΄μ˜ xμ’Œν‘œκ°’μ„ κΈ°μ€€μœΌλ‘œ μ •λ ¬
D.sort(key=lambda d: d[0])

# μž¬κ·€ 호좜
closest_pair(0, N)
print(minD)

μ–΄λ ΅λ‹€..νŒŒμ΄νŒ…

'DevLog πŸ“¨ > Baekjoon' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[DevLog][Baekjoon] 8983: 사λƒ₯κΎΌ  (0) 2023.08.16
[DevLog][Baekjoon] 2110: 곡유기 μ„€μΉ˜  (0) 2023.08.16
[DevLog][Baekjoon] 1629: κ³±μ…ˆ  (0) 2023.08.14
[BaekJoon] 1007: 벑터 맀칭  (0) 2023.02.16
[BaekJoon] 1005: ACM Craft  (0) 2023.02.14