[PYTHON] 백준 8983 - 사냥꾼

이또삐(이민혁)·2023년 4월 14일

CODINGTEST

목록 보기
40/96
post-thumbnail

성능 요약

메모리: 116532 KB, 시간: 324 ms

분류

정렬, 이분 탐색

문제 설명

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라고 하면, 점선으로 표시된 영역은 왼쪽에서 세 번째 사대에서 사냥이 가능한 영역이다.

https://camo.githubusercontent.com/85ecb3b1b07e4fd0ec0b83c33afdbd9393a7a7733196dcd80d17f092fd2c0024/68747470733a2f2f75706c6f61642e61636d696370632e6e65742f38306465376462612d623832322d346633302d623833332d6465333037316166333835622f2d2f707265766965772f

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

입력

입력의 첫 줄에는 사대의 수 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보다 작거나 같은 양의 정수이다.

출력

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


아이디어, 문제풀이

  • 사대마다 축이동을 통해서, a+b를 합친 값을 활용해 보기로 함
  • 시간복잡도를 줄이기 위해 이분탐색 알고리즘을 적용함

TROUBLE SHOOTING

  • 일단 정말 뿌듯하게도, 에러를 마주하고나, 알고리즘 구현에 있어서 막히는 부분은 없었다. 대신, 백준에서 제공하는 태스크표에 의하면 첫 제출은 60점이 나왔어서, 100점을 맞기위한 해결방법과, 코드를 구현하기 위해 학습했던 코드를 소개할까 한다.

  • 우선, 기존에 존재하는 배열을 복사해서, 각 연산에 사용하게끔 할 수있는 코드다.

    #새로운 배열을 복사해서 사용
    new_n_list = [n_list[i].copy() for i in range(n)]

    앞으로도 자주 쓰일것 같다.

  • 문제의 큰 틀에서 봤을때, 내가 생각한 알고리즘을 유지한채로 시간복잡도를 줄여야 했다. 완전탐색으로 구현했던 코드이기에, 문제의도에 좀더 가까운 이분탐색 알고리즘을 적용하고자 했다. 핵심 코드는 역시 이분탐색이다.

    while start <= end:
            mid = (start + end) // 2
            dist = abs(m_list[mid] - x) + y
    
            if dist <= l:
                catch += 1
                break
            elif m_list[mid] < x:
                start = mid + 1
            else:
                end = mid - 1

    dist = abs(m_list[mid] - x) + y 는 앞서 이야기 했던 축 이동을 통한 x, y값 합을 통해 거리를 설정해줬다.


코드

첫 아이디어 - 60점

#https://www.acmicpc.net/problem/8983
#사냥꾼
#8983

import sys
input = sys.stdin.readline

m, n, l = map(int, input().split())
m_list = list(map(int, input().split()))

n_list = []
for i in range(n):
    x = list(map(int, input().split()))
    n_list.append(x)

#print(m_list)
#print(n_list)

sum_list = []
for i in range(n):
    a = sum(n_list[i])
    sum_list.append(a)
#print(sum_list)

catch = [0] * n
# print(sum_list)

#새로운 배열을 복사해서 사용
new_n_list = [n_list[i].copy() for i in range(n)]

# minus_list = [0] * n
# n = 동물의 수 m= 사대의 수 l = 사정거리
for i in range(m):
    for j in range(n):
        new_n_list[j][0] = n_list[j][0] - m_list[i]

    # print(new_n_list)
    plus_list = []
    for j in range(n):
        alpa = abs(new_n_list[j][0]) + abs(new_n_list[j][1])
        plus_list.append(alpa)

    # print(plus_list)

    for j in range(n):
        if plus_list[j] <= l:
            catch[j] = 1

print(sum(catch))

완성된 코드 - 100점

#https://www.acmicpc.net/problem/8983
#사냥꾼
#8983

import sys
input = sys.stdin.readline

m, n, l = map(int, input().split())
m_list = list(map(int, input().split()))

n_list = []
for i in range(n):
    x = list(map(int, input().split()))
    n_list.append(x)

m_list.sort()

catch = 0

for i in range(n):
    x, y = n_list[i]
    start = 0
    end = m - 1

    while start <= end:
        mid = (start + end) // 2
        dist = abs(m_list[mid] - x) + y

        if dist <= l:
            catch += 1
            break
        elif m_list[mid] < x:
            start = mid + 1
        else:
            end = mid - 1

print(catch)
profile
해보자! 게임 클라 개발자!

0개의 댓글