[문제해결 - 정렬] BOJ8983 / 사냥꾼 / 골드4 (Python, 파이썬)

oldshoe·2025년 4월 2일
0

알고리즘 문제

목록 보기
27/51

문제

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보다 작거나 같은 양의 정수이다.

출력

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

서브태스크

예제 입력 1

4 8 4
6 1 4 9
7 2
3 3
4 5
5 1
2 2
1 4
8 4
9 4

예제 출력 1

6

예제 입력 2

1 5 3
3
2 2
1 1
5 1
4 2
3 3

예제 출력 2

5

문제 해결 과정

처음에 해결하기 위해서 동물의 위치를 기준으로 생각을 했다. 사대는 x축에 고정이 되어있기 때문에 각 동물들의 위치에 따라 거리를 계산하는 전형적으로 오래 걸리는(?) 방법을 택했다.
그러다보니, 확실히 서브태스크 뒷 부분, 데이터의 양이 많아졌을 때는 시간 초과로 통과하지 못했다.

M, N, L = map(int, input().split())

x_list = list(map(int, input().split()))

x_list.sort()

anmial_list = []
for _ in range(N) :
    x, y = map(int, input().split())
    anmial_list.append((x,y))
cnt = 0
anmial_list.sort() 
for i in anmial_list :
    if i[1] > L : pass
    for j in x_list :
        if abs(i[0]-j) + i[1] <= L : 
            cnt += 1
            break

print(cnt)

그러다가 한 시간 이상 고민했을 때, 어느 블로그를 참고했는데 사대를 기준으로 생각하는 것이다.
왜냐하면, 동물들의 위치는 x, y에 다 고루 분포되어있기 때문에 모두 확인하려면 for문 두 번을 돌아야하지만, 사대는 x축 위에만 있기 때문에 for 또는 while문 하나면 해결할 수 있다.
사대가 있을 수 있는 최대 값과 최소 값을 설정하고 설정한 값 중에 사대와 가장 가까운 값이 나오면 그 때마다 카운트를 하면 된다.

최종 코드

M, N, L = map(int, input().split())

x_list = list(map(int, input().split()))
animal_list = []
for _ in range(N) :
    x, y = map(int, input().split())
    animal_list.append((x,y))
cnt = 0
x_list.sort()

for i in animal_list :
    
    if i[1] > L :
        continue
    
    max = i[0] - i[1] + L # 사대의 최대 값
    min = i[0] + i[1] - L # 사대의 최소 값
    left, right = 0, M-1
    while left <= right :
        mid = (left+right)//2
        if x_list[mid] >= min and x_list[mid] <= max :
            cnt += 1
            break
        elif x_list[mid] < min :
            left = mid + 1
        else :
            right = mid - 1
            
print(cnt)
profile
toomuxi : There are many things in the world that I want to do

0개의 댓글