학습 철학 회고
그리디 알고리즘은 직관적으로 풀기 쉽다는 함정이 있습니다. "그냥 지금 제일 좋아 보이는 걸 고르면 되는 거 아니야?"라는 생각으로 접근하다가 수많은 반례(Edge Case)에 부딪혀 무너지곤 합니다. 이번에는 감각에 의존하는 코딩을 멈추고, '탐욕'이 수학적인 정답으로 귀결되기 위해 반드시 갖춰야 할 이론적 전제 조건을 뼈대로 세웁니다.
미래를 내다보지 않고, "오직 현재 상태에서 가장 최선이라고 생각되는 선택"만을 반복하여 최종 해답에 도달하는 방법론입니다.
하지만 모든 문제에 그리디를 적용할 수는 없습니다. 눈앞의 마시멜로를 당장 먹는 것이 최종적으로는 손해일 수 있기 때문입니다. 따라서 그리디가 완벽한 알고리즘으로 작동하려면 다음 두 가지 절대 조건이 모두 성립해야 합니다.
그리디 알고리즘 자체는 DFS나 이분 탐색처럼 정형화된 코드 템플릿(자료구조)이 존재하지 않습니다. 문제마다 '탐욕의 기준'이 다르기 때문입니다.
하지만 거의 모든 그리디 코딩 테스트 문제에는 공통된 뼈대가 있습니다. 바로 가장 좋은 것을 빠르게 뽑아내기 위해, 데이터를 특정한 기준에 맞춰 '정렬(Sort)'하거나 '우선순위 큐(Min-Heap)'에 담아두고 시작한다는 점입니다.
정형화된 코드는 없지만, SOP(설계 주도형 사고) 관점에서 그리디 문제를 마주했을 때 전개해야 하는 사고의 흐름과 뼈대 로직은 다음과 같습니다.
def greedy_template(data):
# 1. [핵심] 탐욕의 기준 설정 및 정렬
# (예: 회의가 끝나는 시간이 빠른 순, 무게가 가벼운 순 등)
data.sort(key=lambda x: (x[1], x[0]))
# 또는 heapq.heapify(data) 사용
answer = 0
current_state = 0 # 현재 상태를 추적할 변수
# 2. 정렬된 데이터를 순회하며 탐욕적 선택 진행
for item in data:
# 3. [방어 로직] 현재 아이템이 제약 조건을 만족하는가? (가지치기)
if is_valid(item, current_state):
# 4. 선택 및 상태 갱신
answer += item.value
current_state = item.end_time # 다음 선택을 위한 상태 업데이트
return answer
.sort()를 호출하는 대신 으로 값을 뽑아주는 heapq를 사용하는 것이 완벽한 그리디 구현체입니다. (예: 백준 1715 카드 정렬하기)