그리디 알고리즘(욕심쟁이 알고리즘, Greedy Algorithm)이란 "매 선택에서 지금 이 순간 당장 최적인 답을 선택하여 적합한 결과를 도출하자" 라는 모토를 가지는 알고리즘 설계 기법이다.
그리디 알고리즘의 대표적 예제는 거스름 돈 문제입니다.
우리가 흔히 거스름 돈을 줄 때 가장 적은 양의 화폐를 주는 것이 제일 편합니다. 예를들어 560원을 걸러주어야 할 때 10원 짜리 56개를 주는 것 보다 500원 짜리 1개, 50원짜리 1개, 10원 짜리 1개를 주는 것이 총 3개로 더 편합니다. 따라서 이런 경우 '무조건 더 큰 화폐단위부터 거슬러 준다'는 알고리즘만 지키면 최적의 해를 보장 할 수 있습니다.
이러한 그리디 알고리즘은 기본적으로 무조건 큰 경우, 무조건 작은 경우, 무조건 긴 경우, 무조건 짧은 경우대로 등 극단적으로 문제에 접근한다는 점에서 정렬(Sort)기법이 함께 사용됩니다. 그 대표적인 예시가 크루스칼(Kruskal) Algorithm 으로 모든 간선을 정렬한 이후에 가장 짧은 간선부터 연결하는 최소 비용 신장 트리 알고리즘이다.
단, 그리디 알고리즘을 사용하면 매 선택이 그 순간에 대해서는 최적이지만 그걸 종합적으로 봤을 땐 최적이라는 보장은 절대 없다는 것을 명심해야 한다. 위의 예시에서 매 순간 최적을 따라가면 1-1-1-100라는 순서로 가는데, 중간에 1-1-10-10으로 움직이는 것이 전체적으로 더 짧은 길이 될 수 있으니 말이다.
그리디 알고리즘을 한마디로 설명한다면 그 유명한 마시멜로 실험에 비유할 수 있겠다. 그리디 알고리즘을 사용한다는 것은 지금 당장 눈 앞에 있는 마시멜로를 먹는 것이다. 하지만 이 방법을 사용하는 것은 "기다렸다가 2개를 먹는다"라는 최적해를 보장해주지 못한다.
#include <iostream>
using namespace std;
int main(void)
{
int n, result = 0;
cin >> n;
result += n / 500;
n %= 500;
result += n / 100;
n %= 100;
result += n / 50;
n %= 50;
result += n / 10;
cout << result;
return 0;
}
예제 : 회의실 예약
- 회사에 회의실이 하나 밖에 없는데, n(<=100)개의 팀이 각각 회의하고 싶은 시간을 그림 10.1과 같이 제출했다고 할때, 이 중 서로 겹치지 않는 회의들만을 골라서 진행해야 한다. 최대 몇개나 선택할 수 있을까?
무식하게 풀 수 있을까?
- 이 문제를 무식하게 푸는 방법은 모든 부분 집합을 하나하나 만들어 보며 그중 회의들이 겹치지 않는 답들을 걸러내고 그중 가장 큰 부분 집합을 찾아낸다.
- 그러나 집합의 크기가 n일 때 부분 집합의 수는 2^n이기 때문에 n이 30만 되어도 시간 안에 문제를 풀기는 힘들다.
탐욕적 알고리즘의 구상
- 이 문제를 해결하는 탐욕적인 방법은 길이와 상관 없이 가장 먼저 끝나는 회의부터 선택하는 것이다.
- 목록 S에 남은 회의 중 가장 일찍 끝나는 회의 S(min)을 선택한다.
- S(min)과 겹치는 회의를 S에서 모두 지운다.
- S가 텅 빌 때까지 반복한다.
정당성의 증명 1 : 탐욕적 선택 속성
- 탐욕적 알고리즘의 정당성 증명은 많은 경우 일정한 패턴을 가진다.
- 우리가 처음으로 증명해야할 속성은 동적 계획 법처럼 답의 모든 부분을 고려하지 않고 탐욕적으로만 선택하더라도 최적해를 구할 수 있다는 것이다. -> 탐욕적 선택속성(greed choice property)
- 앞서 제한 한 알고리즘의 경우, 탐욕적 선택 속성이 성립한다는 말은 다음 조건이 성립한다는 의미이다.
가장 종료 시간이 빠른 회의 S(min)를 포함하는 최적해가 만드시 존재한다.
정당성의 증명 2 : 최적 부분 구조
- 항상 최적의 선택만을 내려서 전체 문제의 최적해를 얻을 수 있을음 보여야 한다.
- 부분 문제의 최적해에서 전체 문제의 최적해를 만들 수 있음을 보여야한다.
구현
- 전체 시간 복잡도 O(n^2)
'개발자 > Algorithm' 카테고리의 다른 글
c++ STL 함수 remove, remove_if (0) | 2021.04.22 |
---|---|
프로그래머스 문제풀이(정렬)- K번째수 (0) | 2020.10.20 |
DP 동적 프로그래밍 설명 + 예제(타일링 문제) (0) | 2020.08.05 |
알고 코테 공부 순서 (0) | 2020.08.05 |
C++ 알고리즘 문제 풀이(BFS) (0) | 2020.08.03 |