그리디, 당장 좋은 것
그리디(Greedy) 알고리즘은 단순하지만 강력한 PS 알고리즘이다. 탐욕법
이라고도 부르는 이 알고리즘은 이름에서 알 수 있듯이 어떠한 문제를 단순 무식하게, 탐욕적으로 해결한다. 매 순간 가장 좋아보이는 것을 선택하며, 현재의 선택이 나중에 미칠 영향에 대해서는 고려하지 않는다.
기준에 따라 좋은 것을 선택하는 알고리즘이므로 문제에서 가장 큰(작은) 순서대로
와 같은 힌트를 알게 모르게 제시해준다. 보통 이 기준은 정렬 알고리즘
과 자주 사용된다.
거스름돈
500원, 100원, 50원, 10원짜리 동전이 있을 때 손님에게 거슬러 줘야할 동전의 최소 개수를 구하는 문제이다. (단, 거슬러 줘야할 돈 N은 항상 10의 배수이다.)
풀이
1 | money = int(input()) |
앞서 설명했듯이 문제에 동전의 “최소 개수”를 구하라고 명시되어 있다. 또한 그리디로 해결할 수 있는 이유는 큰 단위가 항상 작은 단위의 배수임으로 작은 단위의 동전들을 종합해 다른 해가 나올 수 없기 때문이다. 시간복잡도는 화폐의 종류가 K개라고 할 때 O(K)
가 된다.
큰 수의 법칙
다양한 수로 이뤄진 배열이 있을 때 주어진 수들을 M번 더하여 가장 큰 수를 만든다. 단, 배열의 특정한 인덱스(번호)에 해당하는 수가 연속해서 K번을 초과하여 더해질 수 없다.
예) [2,4,5,4,6]
, M=8
, K=3
일 때 6+6+6+5+6+6+6+5=46
첫번째 풀이
1 | n,m,k=map(int,input().split()) |
결국 필요한 수는 가장 큰 수와 두번째로 큰 수이다. 가장 큰 수를 반복하다가, 같은 수가 K번이 넘을 때 두번째로 큰 수를 끼워주면 되기 때문이다.
하지만 위와 같은 방식은 수가 커질수록 비효율적이게 된다.
반복되는 수열에 대해서 파악해야 한다.
두번째 풀이
1 | n,m,k=map(int,input().split()) |
전체적으로 가장 큰 수가 필요한 경우, 두번째로 큰 수가 필요한 경우(결국 전체 개수 M에서 가장 큰 수를 쓴 횟수를 뺀 값이 된다)를 구하면 끝나는 문제이다.
숫자 카드 게임
여러 개(N*M)의 숫자 카드 중에서 가장 높은 숫자가 쓰인 카드 한장을 뽑는다. 단, 선택된 행의 가장 낮은 숫자 카드를 뽑는다.
풀이
1 | N,M=map(int,input().split()) |
간단하다. 입력받음과 동시에 가장 작은 수를 num
배열에 넣고 마지막에 최대값을 출력해주면 된다.
1이 될 때까지
어떤 수 N이 1이 될 때까지 나누거나 뺀다. 방법은 두가지이다.
- N에서 1을 뺀다
- N을 K로 나눈다 (단, N이 K로 나누어 떨어질때만)
첫번째 풀이
1 | n,k=map(int,input().split()) |
최대한 많이 나누면 된다. 1을 빼는 것보다 나눌 때 숫자가 훨씬 빨리 작아지기 때문이다. N이 K의 배수가 되도록 한번에 뺀다면 좀 더 효율적으로 짤 수 있다.
두번째 풀이
1 | n,k=map(int,input().split()) |
N을 K의 배수가 되도록 만들고 나머지 경우를 빼주면 된다.