출처: 백준 온라인 저지
https://www.acmicpc.net/problem/1202
from sys import stdin
from bisect import bisect_left
n, k = map(int, stdin.readline().split())
jewels = []
for _ in range(n):
jewels.append([int(x) for x in stdin.readline().split()])
# 무게를 기준으로 오름차순 정렬
jewels.sort(key=lambda x: x[0])
# 가격을 기준으로 내림차순 정렬
jewels.sort(key=lambda x: x[1], reverse=True)
weights = []
for _ in range(k):
weights.append(int(stdin.readline()))
weights.sort()
visited = [False] * (k + 1)
total, i = 0, 0
for jw in jewels:
current = bisect_left(weights, jw[0])
while visited[current]:
current += 1
if current < k:
total += jw[1]
visited[current] = True
print(total)
보석의 (무게, 가격) 쌍(jewels
)은
1) 가격이 높은 것이 먼저 오고
2) 가격이 같을 경우 가벼운 것이 먼저 오도록 정렬하였다.
가방이 담을 수 있는 무게(weights
)는 오름차순으로 정렬하였다.
정렬된 (무게, 가격) 쌍으로 이루어진 jewels
리스트를 for문으로 순회하면서,
이진 탐색으로 해당 보석을 담을 수 있는 가방 중 weights
리스트의 가장 앞에 있는 가방, 즉 담을 수 있는 무게가 가장 적은 가방을 골랐다.
이렇게 매번
그리디
한 방식으로 구현하였다. 알고리즘 자체는 틀리지 않았지만 시간 초과가 떴다.
결국 시간 초과를 해결하지 못하여 다른 풀이들을 참고했다.
우선순위 큐로 최대 힙과 최소 힙을 구현하여 풀 수 있다.
jewels
리스트는 우선순위 큐에 저장하고, weights
리스트는 앞에서와 마찬가지로 무게 순으로 정렬한다.
보석이 아니라 매 가방을 기준으로 가방에 담을 수 있는 보석을 탐색한다. 최소 힙을 통해 매번 가방에 담을 수 있는 모든 보석을 찾고, 그것들의 가격을 새로운 우선순위 큐(jewel_prices
)에 저장한다.
하나의 가방에 담을 수 있는 보석을 찾은 다음, 다음 가방에 담을 수 있는 보석을 찾을 때는, 이전에 탐색이 끝난 지점에서 이어갈 수 있다. 현재 탐색하는 가방은 이전에 탐색한 가방보다 용량이 더 크거나 같으므로, 앞선 가방에 담을 수 있는 보석은 현재 가방에도 담을 수 있기 때문이다.
매번 가방에 담을 수 있는 모든 보석을 찾은 후에는, 그중 가격이 가장 높은 보석을 가방에 담는다. 가방에 담을 수 있는 보석의 가격을 우선순위 큐에 저장했으므로, 최대 힙을 통해 그중 가장 높은 가격 하나를 꺼내면 된다.
위의 풀이를 구현한 코드는 아래와 같다.
from sys import stdin
import heapq
n, k = map(int, stdin.readline().split())
jewels = []
# (무게, 가격) 쌍의 jewels 리스트를 우선순위 큐에 저장
for _ in range(n):
heapq.heappush(jewels, [int(x) for x in stdin.readline().split()])
weights = []
for _ in range(k):
weights.append(int(stdin.readline()))
# 가방을 무게순으로 오름차순 정렬
weights.sort()
total = 0
jewel_prices = []
for bag in weights:
# jewels 리스트를 우선순위 큐에 저장했으므로,
# jewels[0]에는 가장 가벼운 보석의 정보가 들어 있음.
# 현재 탐색 중인 가방이 남은 보석 중 가장 가벼운 보석보다 무겁거나 같다면
while jewels and bag >= jewels[0][0]:
# 최소 힙을 통해 가장 가벼운 보석을 꺼내고, 그 보석의 가격을 current에 저장함.
current = heapq.heappop(jewels)[1]
# 파이썬에는 최소 힙만 존재하므로, 최대 힙은 - 부호를 통해 구현
heapq.heappush(jewel_prices, -current)
if jewel_prices:
# 최대 힙을 통해 가방에 넣을 수 있는 보석의 최대 가격을 total에 더함.
total -= heapq.heappop(jewel_prices)
print(total)