PS❯BOJ2021-11-253 min read
[BOJ 2109] 순회강연 - Java (그리디 & 우선순위 큐)
제한 날짜가 급한 순서로 정렬 후, 날짜별 최대 강연료를 최소 힙(PriorityQueue)으로 유지하며 최적의 강연을 선택하는 그리디 풀이
#BOJ#그리디#우선순위 큐#정렬#Java
1. 문제 개요 및 조건 분석
| 항목 | 내용 |
|---|---|
| 문제 이름 | 순회강연 (백준 2109번 / 골드 3) |
| 플랫폼 / 난이도 | 백준 (골드 3, 2109번) |
| 문제 링크 | 백준 2109번 |
| 제한 사항 | 시간 제한 2초, 메모리 제한 128MB |
| 입력 조건 | 강연 요청 대학 수 $n$ ($0 \le n \le 10,000$), 강연료 $p \le 10,000$, 마감 기한 $d \le 10,000$ |
| 핵심 규칙 | 하루에 최대 한 곳에서만 강연할 수 있을 때, 얻을 수 있는 최대 강연료 수익 구하기 |
2. 접근 아이디어: 그리디 & 최소 힙 (PriorityQueue)
기한 기준 정렬 및 최소 힙 운용
- 기한 오름차순 정렬:
- 강연들을 마감 기한($d$)이 빠른 순서로 정렬합니다. (기한이 같다면 강연료 기준 정렬)
- 최소 힙(PriorityQueue)으로 최적 강연 유지:
- 정렬된 강연을 하나씩 확인하며 강연료를 최소 힙에 삽입합니다.
- 힙에 들어있는 원소의 개수는 **"현재까지 선택하여 진행하기로 한 강연의 수"**이자 **"필요한 총 일수"**입니다.
- 만약 힙의 크기가 현재 강연의 마감일($d$)을 초과하게 되면, 지금까지 선택한 강연 중 가장 강연료가 낮은 강연(
pq.poll())을 버립니다.
- 최종 합산:
- 모든 강연을 확인한 후 힙에 남아있는 모든 강연료를 합산하면 가능한 최대 수익이 됩니다.
flowchart TD
A["강연들을 기한 d 오름차순으로 정렬"] --> B["각 강연의 강연료 p를 최소 힙에 삽입"]
B --> C{"힙 크기 > 현재 강연 기한 d ?"}
C -- Yes --> D["최소 강연료 poll() 제거"] --> E["다음 강연으로 이동"]
C -- No --> E
E --> F["힙에 남은 모든 강연료 합산 출력"]
3. Java 풀이 코드
import java.io.*;
import java.util.*;
public class Main {
static class Lecture implements Comparable<Lecture> {
int pay, day;
Lecture(int pay, int day) {
this.pay = pay;
this.day = day;
}
@Override
public int compareTo(Lecture o) {
if (this.day == o.day) {
return o.pay - this.pay;
}
return this.day - o.day; // 기한 오름차순 정렬
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
Lecture[] lectures = new Lecture[n];
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
lectures[i] = new Lecture(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
}
Arrays.sort(lectures);
// 강연료를 담을 최소 힙
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (Lecture lec : lectures) {
pq.add(lec.pay);
// 선택된 강연 수가 기한을 넘어가면 가장 싼 강연을 포기
if (pq.size() > lec.day) {
pq.poll();
}
}
int total = 0;
while (!pq.isEmpty()) {
total += pq.poll();
}
System.out.println(total);
}
}
4. 복잡도 분석
- 시간 복잡도: $O(N \log N)$ — 정렬 $O(N \log N)$ + 각 원소당 힙 삽입/삭제 $O(\log N)$. $N = 10,000$이므로 0.2초 이내 여유 있게 완료.
- 공간 복잡도: $O(N)$ — 배열 및 우선순위 큐 메모리.
5. 채점 결과 및 통과 인증

← PREVIOUS LOG
[BOJ 4196] 도미노 - Java (SCC 강한 연결 요소 & 진입차수 in-degree 카운트)
NEXT LOG →[BOJ 3977] 축구 전술 - Java (SCC 강한 연결 요소 & 진입차수 0 판별)
COMMENTS // GITHUB DISCUSSIONS (GISCUS)