https://www.acmicpc.net/problem/8983
8983번: 사냥꾼
입력의 첫 줄에는 사대의 수 M (1 ≤ M ≤ 100,000), 동물의 수 N (1 ≤ N ≤ 100,000), 사정거리 L (1 ≤ L ≤ 1,000,000,000)이 빈칸을 사이에 두고 주어진다. 두 번째 줄에는 사대의 위치를 나타내는 M개의 x-좌
www.acmicpc.net
문제

문제 해설
(1) 총을 쏘는 사대, 동물의 위치 좌표가 총의 사정거리와 함께 주어진다.
(2) 모든 동물 중, 잡을 수 있는 동물의 최댓수를 출력하면 된다.
문제 풀이
아주 다양한 아이디어가 떠올라서 시도했으나 자꾸 60점에서 막혔었다 ㅠㅠ 알고보니 이진탐색을 적용해야 효과적인 부분이었고, 풀고나니 이진탐색 적용할 부분도 사실 어렵지 않게 떠올릴 수 있는 유형이었는데 왜 그걸 생각을 못했을까.
문제풀이 아이디어는 거의 곧바로 떠올랐었다.
1. 우선, 60점 부분점수를 맡을 때의 풀이 아이디어는 총을 쏘는 사대를 기준으로 완전탐색을 진행하는 것이었다.
for x_shot in shot_spot:
for k in list(animal_spot.keys()):
if animal_spot[k] != 1:
continue
x_anim, y = k
if abs(x_anim - x_shot) + y <= L:
answer += 1
del (animal_spot[k])
총을 쏘는 사대를 기준으로 모든 동물의 위치를 탐색해서, 현재 사대에서 쏠 수 있는 거리인지 dictionary를 이용해 체크 후, 잡을 수 있다면 해당 dictionary에서 삭제하는 형식으로 진행했다. 풀면서도 마지막 sub task는 통과 못하겠다 생각했고, 결과도 그래서 다른 아이디어를 떠올렸다.
2. 그래서 사대가 아닌, 사냥감을 기준으로 탐색하고자 하였다.
for spot in animal_spot:
x_anim, y = spot
if y > L:
continue
max_range = max(x_anim - (L - y), x_anim + (L - y))
min_range = min(x_anim - (L - y), x_anim + (L - y))
for p in range(min_range, max_range + 1):
if p in shot_spot:
answer += 1
break
사냥감에 접근 가능한 범위 (x_min, x_max)는 간단히 구할 수 있고, 해당 범위에 사대가 있는지 체크하면 된다. 직관적으로 탐색할 범위가 사대의 개수보다 줄어들지 않을까?까지만 생각했는데, 오히려 41점을 맞아서 다른 아이디어가 있는지 생각에 빠졌었다. 그냥 여기서 저 접근가능한 범위를 전체탐색이 아닌, 이분탐색으로 찾으면 될 것을 한참을 헤맨 것이다.
3. 그래서 다시 돌아와서 사냥감 기준 탐색에 이분탐색을 적용하였고, 아래와 같이 풀 수 있게 되었다. 추가로 y값이 L보다 크다면 애초에 탐색할 필요도 없기에(어떤 사대에서도 접근 불가능) input 받을 때 걸러주는 코드도 추가하였다.
* 코드
from sys import stdin
import heapq
M, N, L = map(int, stdin.readline().rstrip().split())
shot_spot = sorted(list(map(int, stdin.readline().rstrip().split())))
animal_spot = []
answer = 0
for i in range(N):
x, y = map(int, stdin.readline().rstrip().split())
if y > L:
continue
heapq.heappush(animal_spot, (y, (x, y)))
while len(animal_spot) > 0:
x_anim, y = heapq.heappop(animal_spot)[1]
max_range = max(x_anim - (L - y), x_anim + (L - y))
min_range = min(x_anim - (L - y), x_anim + (L - y))
start = 0
end = len(shot_spot) - 1
while start <= end:
target = (start + end) // 2
if shot_spot[target] >= min_range and shot_spot[target] <= max_range:
answer += 1
break
if shot_spot[target] > max_range:
end = target - 1
else:
start = target + 1
print(answer)'💡코딩테스트 > NORMAL' 카테고리의 다른 글
| [BAEKJOON] 1654_랜선 자르기_Python (0) | 2022.09.24 |
|---|---|
| [Programmers]단어 변환_Python (0) | 2022.09.24 |
| [BAEKJOON] 1012_유기농 배추_Python (0) | 2022.09.21 |
| [BAEKJOON] 14889_스타트와 링크_Python (1) | 2022.09.21 |
| [BAEKJOON] 15654_N과 M(9)_Python (1) | 2022.09.21 |