안 쓰던 블로그

탐욕 알고리즘(greedy algorithm) 본문

알고리즘/Algorithm

탐욕 알고리즘(greedy algorithm)

proqk 2019. 5. 9. 20:47
반응형

탐욕 알고리즘이란?

탐욕법이란 이름 그대로 눈 앞에 보이는 최선을 탐욕적으로 선택하는 것을 반복하는 알고리즘 설계 패러다임 중 하나입니다. 탐욕법을 이용한 일고리즘을 탐욕 알고리즘, 그리디 알고리즘이라고 합니다. 전체를 여러 조각으로 나눠서 각 단계마다 답의 일부를 만들어 간다는 점에서 완전 탐색과 비슷하지만, 모든 선택지를 보는 완전 탐색과 달리 탐욕 알고리즘은 지금 당장 가장 좋은 해답을 선택합니다. 탐욕 알고리즘의 대표적인 문제로는 각 물건의 무게와 가치가 주어졌을 때, 가방에 가치가 높은 물건을 최대한 많이 담는 경우를 찾는 배낭 문제(Knapsack problem)이 있습니다.

 

 

탐욕 알고리즘의 한계

탐욕 알고리즘은 매 순간 가장 좋은 선택지만 고르기 때문에 전체적으로 봤을 때 더 좋은 선택지가 있어도 발견하지 못합니다. 지금의 선택이 이후에 어떤 영향을 끼칠지를 고려하지 않죠. 그러면 최적인 해답을 찾지 못하는데 왜 사용할까요? 탐욕 알고리즘을 사용하는 경우는 크게 두 가지입니다.

 

1. 탐욕 알고리즘으로 최적의 해답을 찾아도 되는 경우

2. 학문적으로써의 알고리즘 분야에서 인간이 아직 풀지 못한 문제를 풀 때 정확한 최적의 해답을 찾기보다는 근사해를 구하는 경우. 더 적은 시간과 비용으로 비슷한 해답을 찾아낼 수 있습니다.

 

프로그래밍 대회에서는 대부분 1번의 이유로 탐욕 알고리즘을 사용합니다. 2번처럼 근사해를 찾는 경우는 거의 없다고 봐도 될 것 같습니다. 당장은 그런 문제를 만날 일도 없을테니까, 탐욕 알고리즘은 상황과 문제에 따라 사용하시면 되겠습니다.

 


 

https://www.acmicpc.net/problem/11399

예시 문제를 풀어보겠습니다. ATM을 쓰기 위해서 사람들이 줄을 서 있습니다. 각 사람 별로 돈을 인출하는데 걸리는 시간이 주어졌을 때, 가장 빨리 모든 사람들이 돈을 뽑는 경우의 시간을 구하는 문제입니다.

 

 

완전 탐색으로 풀 수 있을까?

무식하고 가장 간단하게 풀고자 하면 줄 세우는 모든 경우의 수를 전부 돌면서 가장 적은 시간을 찾아내면 되겠네요. 그런데 이 경우, 최대 사람의 수는 1000이고 1000가지를 나열하는 모든 경우의 수는 1000!이니까 딱 보기에도 시간 제한 1초 안에 풀기는 힘들어집니다. 차라리 다른 은행 가는 게 더 빠르겠습니다.

 

 

탐욕 알고리즘

더 효율적인 탐색 방법을 생각해봅시다. 모든 사람이 가장 빠르게 돈을 뽑기 위해서는 뒷사람들이 기다리는 시간을 줄이면 되겠네요. 빠른 사람부터 뽑으면 뒷사람들이 기다리는 시간이 줄어드니까, 최종적으로는 전체 시간이 줄게 됩니다. 빠른 사람 순으로 오름차순 정렬을 한 뒤에 계산을 하면 답이 나옵니다.

#include <stdio.h>
#include <algorithm>
int n, p[1005], res = 0;
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &p[i]);
 
    std::sort(p, p + n);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            res += p[j];
        }
    }
    printf("%d", res);
}

 

탐욕 알고리즘을 쓰는 문제는 뭔가를 가장 빨리~, 가장 큰~ 이라는 단어가 많이 들어갑니다. 정렬을 잘 알아두면 문제를 푸는 데에 도움이 될 듯합니다. 문제를 보고 완전탐색으로 풀기에는 경우의 수가 큰데, 뒷일은 생각하지 않고 각 단계에서 최선을 택해도 정답을 구할 수 있을 것 같을 때 탐욕 알고리즘을 사용하면 됩니다.

 

 

추천문제

https://www.acmicpc.net/problem/11399

 

11399번: ATM

첫째 줄에 사람의 수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어진다. (1 ≤ Pi ≤ 1,000)

www.acmicpc.net

https://www.acmicpc.net/problem/11047

 

11047번: 동전 0

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000) 둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

www.acmicpc.net

https://www.acmicpc.net/problem/5585

 

5585번: 거스름돈

문제 타로는 자주 JOI잡화점에서 물건을 산다. JOI잡화점에는 잔돈으로 500엔, 100엔, 50엔, 10엔, 5엔, 1엔이 충분히 있고, 언제나 거스름돈 개수가 가장 적게 잔돈을 준다. 타로가 JOI잡화점에서 물건을 사고 카운터에서 1000엔 지폐를 한장 냈을 때, 받을 잔돈에 포함된 잔돈의 개수를 구하는 프로그램을 작성하시오. 예를 들어 입력된 예1의 경우에는 아래 그림에서 처럼 4개를 출력해야 한다. 입력 입력은 한줄로 이루어져있고, 타로가 지불할

www.acmicpc.net

https://www.acmicpc.net/problem/2217

 

2217번: 로프

N(1≤N≤100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다. 하지만 여러 개의 로프를 병렬로 연결하면 각각의 로프에 걸리는 중량을 나눌 수 있다. k개의 로프를 사용하여 중량이 w인 물체를 들어올릴 때, 각각의 로프에는 모두 고르게 w/k 만큼의 중량이 걸리게 된다. 각 로프들에 대한 정보가 주어졌을 때, 이 로프들을

www.acmicpc.net

https://www.acmicpc.net/problem/1202

 

1202번: 보석 도둑

문제 세계적인 도둑 상덕이는 보석점을 털기로 결심했다. 상덕이가 털 보석점에는 보석이 총 N개 있다. 각 보석은 무게 Mi와 가격 Vi를 가지고 있다. 상덕이는 가방을 K개 가지고 있고, 각 가방에 담을 수 있는 최대 무게는 Ci이다. 가방에는 최대 한 개의 보석만 넣을 수 있다. 상덕이가 훔칠 수 있는 보석의 최대 가격을 구하는 프로그램을 작성하시오. 입력 첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000) 다음 N개 줄에는 각 보석의

www.acmicpc.net

 

반응형
Comments