[WEEK02] 백준 8983 사냥꾼

UBIN·2023년 4월 20일
0

문제

KOI 사냥터에는 N 마리의 동물들이 각각 특정한 위치에 살고 있다. 사냥터에 온 사냥꾼은 일직선 상에 위치한 M 개의 사대(총을 쏘는 장소)에서만 사격이 가능하다. 편의상, 일직선을 x-축이라 가정하고, 사대의 위치 x1, x2, ..., xM은 x-좌표 값이라고 하자. 각 동물이 사는 위치는 (a1, b1), (a2, b2), ..., (aN, bN)과 같이 x,y-좌표 값으로 표시하자. 동물의 위치를 나타내는 모든 좌표 값은 양의 정수이다.

사냥꾼이 가지고 있는 총의 사정거리가 L이라고 하면, 사냥꾼은 한 사대에서 거리가 L 보다 작거나 같은 위치의 동물들을 잡을 수 있다고 한다. 단, 사대의 위치 xi와 동물의 위치 (aj, bj) 간의 거리는 |xi-aj| + bj로 계산한다.

예를 들어, 아래의 그림과 같은 사냥터를 생각해 보자. (사대는 작은 사각형으로, 동물의 위치는 작은 원으로 표시되어 있다.) 사정거리 L이 4라고 하면, 점선으로 표시된 영역은 왼쪽에서 세 번째 사대에서 사냥이 가능한 영역이다.

사대의 위치와 동물들의 위치가 주어졌을 때, 잡을 수 있는 동물의 수를 출력하는 프로그램을 작성하시오.

입력

입력의 첫 줄에는 사대의 수 M (1 ≤ M ≤ 100,000), 동물의 수 N (1 ≤ N ≤ 100,000), 사정거리 L (1 ≤ L ≤ 1,000,000,000)이 빈칸을 사이에 두고 주어진다. 두 번째 줄에는 사대의 위치를 나타내는 M개의 x-좌표 값이 빈칸을 사이에 두고 양의 정수로 주어진다. 이후 N개의 각 줄에는 각 동물의 사는 위치를 나타내는 좌표 값이 x-좌표 값, y-좌표 값의 순서로 빈칸을 사이에 두고 양의 정수로 주어진다. 사대의 위치가 겹치는 경우는 없으며, 동물들의 위치가 겹치는 경우도 없다. 모든 좌표 값은 1,000,000,000보다 작거나 같은 양의 정수이다.

출력

출력은 단 한 줄이며, 잡을 수 있는 동물의 수를 음수가 아닌 정수로 출력한다.

풀이

리스트를 만들고 사대의 위치를 오름차순으로 저장해주었다.
이후에 동물들의 좌표를 받을때마다 동물의 x좌표가
사대 리스트에 넣을 때 적절한 위치 인덱스를 받아왔다.

def find_correct_index(a, x):
    left, right = 0, len(a) - 1
    result = 0

    while left <= right:
        mid = (left + right) // 2

        if a[mid] == x:
            return mid
        elif a[mid] > x:
            right = mid - 1
            result = mid
        else:
            left = mid + 1
            result = mid + 1

    return result       

예를 들어 [1, 3, 5, 7, 10] 이라는 리스트가 있을 때
find_correct_index(a, 4) = 2
find_correct_index(a, 3) = 1

이렇게 얻어온 인덱스는 현재 동물과 가장 가까운 사대의 인덱스를 반환하는 것이 아니다.

첫번째로 가까운지 두번째로 가까운지는 확실하지 않다.
때문에 return 값을 index 라고 한다면
index, index - 1 의 인덱스를 가지는 두 개의 사대를 비교해줘야 한다.

이렇게 2개의 사대를 검사해주면 동물과 가장 가까운 사대가 무조건 포함된다.
가까운 2개의 사대에서 동물을 죽일 수 없다면 다른 사대는 당연히 죽이지 못한다.

방법은 아래와 같다

  • 현재 동물과 근접한 사대의 인덱스를 구한다.
  • i라는 값을 반환 받았다면 i, i+1의 인덱스를 가지는 사대와 동물의 거리를 검사해서 죽일 수 있다면 count += 1.
  • 사대의 y좌표는 0으로 고정이니 동물의 y좌표가 사거리보다 크다면 처음부터 제외해준다.

전체코드

def find_correct_index(a, x):
    left, right = 0, len(a) - 1
    result = 0

    while left <= right:
        mid = (left + right) // 2

        if a[mid] == x:
            return mid
        elif a[mid] > x:
            right = mid - 1
            result = mid
        else:
            left = mid + 1
            result = mid + 1

    return result            

m, n, l = map(int, input().split())
sniper_pos = list(map(int, sys.stdin.readline().split()))
sniper_pos = sorted(sniper_pos)
count = 0

for _ in range(n):
    x, y = map(int, sys.stdin.readline().split())
    if y > l: continue

    # 동물의 x좌표가 들어오면 가까운 사대의 인덱스 찾기
    idx = find_correct_index(sniper_pos, x)

    # 가장 가까운 인덱스를 찾은게 아니여서
    # idx 와 idx - 1 -> 2개의 사대와 비교 해야함
    try:
        if abs(sniper_pos[idx] - x) + y <= l:
            count += 1
            continue
    except:
        pass

    try:
        if abs(sniper_pos[idx - 1] - x) + y <= l:
            count += 1
            continue
    except:
        pass

print(count)
profile
ubin

0개의 댓글