1. 문제
세계적인 도둑 상덕이는 보석점을 털기로 결심했다.
상덕이가 털 보석점에는 보석이 총 N개 있다. 각 보석은 무게 Mi와 가격 Vi를 가지고 있다. 상덕이는 가방을 K개 가지고 있고, 각 가방에 담을 수 있는 최대 무게는 Ci이다. 가방에는 최대 한 개의 보석만 넣을 수 있다.
상덕이가 훔칠 수 있는 보석의 최대 가격을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000)
다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000)
다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci ≤ 100,000,000)
모든 숫자는 양의 정수이다.
출력
첫째 줄에 상덕이가 훔칠 수 있는 보석 가격의 합의 최댓값을 출력한다.
2. 정답 코드
import sys import heapq input = sys.stdin.readline n, k = map(int, input().split()) gems = [] for _ in range(n): heapq.heappush(gems, list(map(int, input().split()))) bags = [] for _ in range(k): bags.append(int(input())) bags.sort() q = [] answer = 0 for bag in bags: while gems and bag >= gems[0][0]: # 모든 보석을 찾는데 각 보석의 무게가 배낭의 용량을 넘지 않을 때 배낭에 넣기 heapq.heappush(q, -heapq.heappop(gems)[1]) # 탐색한 보석들을 계속 넣어주는데 결국 최종적으로 가치가 가장 높은 보석을 찾아야 한다. if q: answer -= heapq.heappop(q) # q를 새로 초기화하지 않고 heapop만 계속 해주는 이유는 # 보석과 가방을 무게순으로 정렬하고 탐색하고 있기 때문에 이미 더 가벼운 가방에 # 들어갈 수 있는 보석이면 무거운 가방에도 당연히 들어갈 수 있기 때문에 초기화를 하지 않는다. print(answer)
3. 생각한 방향 및 설명
우선 그냥 그리디하게 풀면되겠다고 처음 생각하였다.
가장 작은
용량의 배낭에 가장 가치
가 높은 보석을 순서대로 넣으면 될 것이다.그러려면 배낭마다(K) 주어진 모든 보석(N)이 배낭의 무게를 초과하지 않으면서 가치가 가장 높은 경우를 찾아야한다.
하지만 주어진 문제 조건에서 N, K가 300000 제한이 있었다. 따라서 최악의 경우
O(N * K)시간이 걸릴것으로 예상되어 시간초과가 될 것이 뻔했다.
따라서 차선책으로 heapq를 이용하기로 하였다.
4. 시간 복잡도 분석
- 보석 정렬 및 삽입:
- 처음에 보석들을 힙(
gems
)에 넣는 과정의 시간 복잡도는O(N log N)
이다.
- 가방 순회:
for bag in bags:
은 가방의 수인K
번 반복된다.
- 내부 루프 (
while gems and bag >= gems[0][0]:
): - 이 루프에서 보석은 각 보석이 한 번씩만
q
로 이동하므로,heappop
과heappush
연산은 각각O(log N)
의 시간 복잡도를 가진다. - 그러나 모든 보석이 한 번만 이동하므로, 전체적으로
N
개의 보석에 대해O(N log N)
의 복잡도가 발생한다. → 한번 성립한 보석은heappop
으로 빠지기 때문… - 이 복잡도는 가방 순회(
K
번 반복)와 독립적이다.
- 최종 시간 복잡도:
- 보석을
q
로 옮기는while
루프의 복잡도는 전체적으로O(N log N)
이다. for
루프 내에서q
힙에서 보석을 선택하는 연산은 각 가방에 대해 한 번씩 발생하며, 이 연산은 최대O(K log N)
이다.- 따라서 두 단계의 시간 복잡도를 더한 최종 복잡도는
O(N log N) + O(K log N)
이 되어, 이는O((N + K) log N)
으로 표현된다.