이 글은 '이것이 코딩테스트다'를 요약하여 그리디 알고리즘에 대하여 설명합니다.
학습 목표
· 그리디 알고리즘이란?
· 예시 - 거스름돈 문제
· 그리디 알고리즘의 정당성
그리디 알고리즘이란?
· 탐욕적으로 문제를 푸는 알고리즘
- 탐욕적이라는 말은 ‘매 순간 가장 좋아 보이는 것만 선택하고 나중에 미칠 영향은 고려하지 않는’ 방식을 의미한다.
· 코딩 테스트에서 만나게 될 그리디 알고리즘 문제 유형의 특징:
- 사전에 외우고 있지 않아도 풀 수 있을 가능성이 높은 문제 유형이다.
- 문제 유형이 매우 다양하여 암기한다고 항상 잘 풀 수 있는 알고리즘 유형이 아니다.
때문에 많은 유형을 접해보고 문제를 풀어보며 훈련 해야 한다.
- 일반적으로 창의력, 즉 문제를 풀기 위한 최소한의 아이디어를 떠올릴 수 있는 능력을 요구한다.
즉, 특정 문제에서 단순히 현재 상황에서 가장 좋아 보이는 것만을 선택해도 문제를 풀 수 있는지 파악할 수 있어야 한다.
- 다익스트라 알고리즘처럼 그리디 알고리즘이면서 암기가 필요한 알고리즘도 일부 존재한다.
- 여러 개의 데이터를 빠르게 정렬해야 하는 문제를 위해 정렬 라이브러리의 사용 방법 숙지해야한다.
- 기준에 따라 좋은 것을 선택하는 알고리즘이므로 문제에서 가장 큰 순서대로, 가장 작은 순서대로와 같은 기준을 알게 모르게 제시한다.
대체로 이 기준은 정렬 알고리즘을 사용했을 때 만족시킬 수 있으므로, 자주 정렬 알고리즘과 짝을 이뤄 출제한다.
▶ 예시 - 거스름돈 문제
당신은 음식점의 계산을 도와주는 점원이다. 카운터에는 거스름돈으로 사용할 500원, 100원, 50원, 10원짜리 동전히 무한히 존재한다고 가정한다. 손님에게 거슬러 줘야 할 돈이 N원일 때 거슬러 줘야할 동전의 최소 개수를 구하라. 단 거슬러 줘야 할 돈 N은 항상 10의 배수이다.
풀이
그리디 알고리즘의 대표적인 유형인 거스름돈 문제다.
이 문제는 ‘가장 큰 화폐 단위부터’ 돈을 거슬러 주는 아이디어로 풀 수 있다.
N원을 거슬러 줘야 할 때, 가장 먼저 500원으로 거슬러 줄 수 있을 만큼 거슬러 준다.
이후 100원, 50원, 10원짜리 동전을 차례대로 거슬러 줄 수 있을 만큼 거슬러 주면 최소의 동전 개수로 모두 거슬러 줄 수 있다.
N = 1,260 이라고 가정하자.
1. 500원짜리로 거슬러 줄 수 있는 돈은 1,000원, 즉 500원 2개이고 남은 돈은 260원이다.
2. 100원짜리로 거슬러 줄 수 있는 돈은 200원, 즉 100원 2개이고 남은 돈은 60원이다.
3. 50원짜리로 거슬러 줄 수 있는 돈은 50원, 즉 50원 1개이고 남은 돈은 10원이다.
4. 10원짜리로 거슬러 줄 수 있는 돈은 10원, 즉 10원 1개이고 거스름돈 계산을 모두 마쳤다.
따라서 N = 1,260 일때 손님이 받은 동전의 최소 개수는 6개이다.
public class 거스름돈문제 {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int money = sc.nextInt(); // 거슬러 줘야할 돈
int num = 0; // 필요한 동전 개수
while (num != 0){
if(money%500 == 0){
money = money/500;
num ++;
}else if(money%100 == 0){
money = money/100;
num ++;
}else if(money%50 == 0){
money = money/50;
num ++;
}else if(money%10 == 0){
money = money/10;
num ++;
}
}
System.out.println("필요한 동전의 개수: " + num);
}
}
그리디 알고리즘의 정당성
· 탐욕적으로 문제에 접근했을 때 정확한 답을 찾을 수 있다는 보장이 있을 때는 매우 효과적이고 직관적이다.
- ex) 거스름돈 문제에서 가장 큰 화폐 단위부터’ 돈을 거슬러 주는 것
- 하지만 대부분의 문제는 그리디 알고리즘을 이용했을 때 최적의 해 찾을 수 없다.
· 그리디 알고리즘으로 문제의 해법을 찾았을 때는 그 해법이 정단한지 검토해야한다.
- 거스름돈 문제는 가지고 있는 동전 중에서 큰 단위가 항상 작은 단위의 배수이므로
작은 단위의 동전들을 종합해 다른 해가 나올 수 없다. 때문에 그리디 알고리즘으로 해결할 수 있었다.
- 반대로 800원을 거슬러 줘야 하는데 화폐 단위가 500원, 400원, 100원인 경우 그리디는
500원 + 100원 + 100원 + 100원 4개의 동전을 거슬러 줘야 한다고 나온다.
하지만 최적해는 400원 + 400원 2개의 동전을 거슬러 주는 것이다.
즉, 화폐 단위가 서로 배수 형태가 아니라면 그리디 알고리즘을 사용할 수 없다. 이때는 다이나믹 프로그래밍으로 해결할 수 있다.
· 코딩테스트에서 문제 유형을 파악하기 어렵다면 그리디 알고리즘을 의심하고, 탐욕적인 해결법이 존재하는지 고민하자.
그리디 알고리즘으로 해결 방법을 찾을 수 없다면, 다이나믹 프로그래밍(DP)이나 그래프 알고리즘 등으로 문제를 해결할 수 있는지 재차 고민하자.
(+)추가적인 그리디 알고리즘 문제풀이
'알고리즘&코딩테스트' 카테고리의 다른 글
[Algorithm] 다이나믹 프로그래밍(동적계획법, Dynamic Programming) (0) | 2021.11.18 |
---|---|
[Algorithm] 구현 문제란? (0) | 2021.11.06 |
[Algorithm] 그래프 이론: 트리, 서로소, 신장 트리, 크루스칼 알고리즘, 위상 정렬 (0) | 2021.11.03 |
[Algorithm] 최단 경로를 찾는 알고리즘 (다익스트라, 플로이드 워셜) (1) | 2021.10.17 |
[Algorithm] 이것이 코딩테스트다 - 이진탐색 문제풀이(with 자바) (0) | 2021.09.13 |
댓글