오늘은 여기까지
그리디 알고리즘 본문
그리디 알고리즘
문제 해결 과정에서 단계마다 눈앞에 최선의 선택을 하고, 선택은 번복하지 않는다.
그리디 알고리즘이 최적해를 보장하려면?
- 최적 부분 구조: 부분해를 푸는 과정이 최적해를 구하는 과정과 일치
- 그리디 선택 속성: 선택 과정이 다른 과정에 영향을 주지 않음
배낭 문제
부분 배낭 문제
짐을 쪼갤 수 있는 배낭 문제를 가정하자.
배낭에 담을 수 있는 최대 무게가 존재하고, 무게와 가치가 다른 짐들이 있다. 이 짐들을 조합해서 배낭의 무게를 초과하지 않으면서 담은 가치를 최대로 하는 문제를 배낭 문제라고 한다.
부분 배낭 문제는 무게당 가치가 높은 짐을 최대한 많이 넣는 그리디 알고리즘을 사용하면 된다.
- 짐별로 무게당 가치를 구한다
- 무게당 가치가 높은 짐부터 넣을 수 있는 만큼 배낭에 넣는다
- 배낭 용량이 짐 무게보다 크면 짐을 쪼개서 넣는다.
- 배낭이 허용하는 용량이 0이 될 때까지 수행한다.
무게당 가치가 제일 높은 짐은 A이므로 먼저 10kg을 배낭에 넣는다.
그 다음으로 가치가 높은 짐 C를 5kg만 넣는다.
0/1 배낭 문제
짐을 쪼갤 수 없는 배낭 문제를 가정하자.
더 이상 짐을 쪼갤 수 없기 때문에 지금 선택한 짐이 다음 짐 선택에 영향을 미친다.
따라서 그리디 알고리즘을 적용하면 최적의 해를 구할 수 없다.
최적의 해를 구하려면 dp로 접근해야 한다.
위와 같은 문제로 예를 들면, 무게당 가치가 높은 짐부터 넣을 시 A를 먼저 10kg 넣게 된다. 가용 용량은 5kg이 남고, 배낭에 넣은 짐의 가치는 19이다.
하지만 B, C를 넣었다면 더 높은 가치인 20으로 짐 13kg을 넣을 수 있다.
이처럼 그리디 알고리즘으로 구한 해가 최적의 해임을 보장하기 위해서는 현재 선택이 다음 선택에 영향을 미치지 않아야 한다.
그리디 vs 동적 프로그래밍
그리디 | 동적 프로그래밍 | |
문제 해결 방식 | 각 단계에서 현재 최적의 선택만 수행 | 부분 문제의 해를 저장하고 재활용하여 전체 문제 해결 |
최적해 보장 | 일부 문제에서만 최적해 보장 | 항상 최적해 보장 |
실행 속도 | 일반적으로 매우 빠름 O(n) 또는 O(n log n) | 일반적으로 그리디보다 느림 O(n²) 이상 |
메모리 사용 | 매우 적음 | 중간~많음 (메모이제이션 테이블 필요) |
적용 가능한 예시 | • 거스름돈 문제 • 회의실 배정 • 크루스칼 알고리즘 • Fractional Knapsack |
• 0/1 Knapsack • 최장 증가 수열(LIS) • 행렬 곱셈 |
성립 조건 | • 최적 부분 구조를 가짐 (부분적인 최적해가 전체 최적해로 이어짐) • 이전 선택이 이후 선택에 영향을 주지 않음 |
• 최적 부분 구조를 가짐 • 중복되는 부분 문제가 존재 |
중복 부분 문제 | 중복 부분 문제를 해결하지 않음 | 중복 부분 문제를 해결할 수 있음 |
시간 복잡도 개선 가능성 | 제한적 | 메모이제이션으로 크게 개선 가능 |
'CS > 자료구조, 알고리즘' 카테고리의 다른 글
최소 신장 트리 (MST) - 크루스칼 알고리즘, 프림 알고리즘 (0) | 2025.01.16 |
---|