그리디
거스름돈
큰 동전부터 주면 되나
동전으로 거스름돈을 만들어 보세요. 줄 수 있는 동전 중 가장 큰 동전부터 한 개씩 줍니다.
1260원을 거슬러 줍니다. 가장 적은 개수로 주는 것이 목표예요. 줄 수 있는 동전 중 가장 큰 동전부터 눌러 한 개씩 줍니다.
남은 돈 1260원
준 동전 0개
- 아직 없음
지금까지 쓴 동전 0개
세트 A는 큰 동전부터 줘서 0개로 끝났습니다. 세트 B는 큰 동전부터 주면 0개인데, 다른 방법으로는 0개입니다.
4 + 1 + 1세트 B 를 큰 동전부터 주면 이렇게 됩니다 (3개).
3 + 3하지만 이렇게 주면 2개입니다.
세트 B · 큰 동전부터3개
세트 B · 가장 적게2개
지금 가장 좋아 보이는 것(가장 큰 동전)을 고르고 되돌리지 않는 방법 = 그리디(greedy)
세트 A 에서는 맞았고 세트 B 에서는 틀렸습니다. 그리디는 늘 맞는 방법이 아닙니다. 모든 경우를 따져 맞게 만드는 방법은 작은 경우부터 표를 채우는 DP 입니다. 앞 장의 0/1 배낭 이 그 예입니다.
큰 동전이 작은 동전의 배수일 때는 맞다
- 세트 A — 500 = 5 × 100, 100 = 2 × 50, 50 = 5 × 10. 큰 동전 하나는 작은 동전 여러 개와 같아서 큰 동전을 줘도 손해가 없다
- 세트 B — 4 는 3 의 배수가 아니다. 4원을 먼저 주는 바람에 3 + 3 이 될 자리를 놓쳤다
- 그래서 — 동전이 서로 배수면 큰 것부터 줘도 된다. 배수가 아니면 틀릴 수 있다
코드는 큰 동전부터 빼 나가는 것이 전부다
다음을 눌러 한 줄씩 넘기며 남은 돈이 줄고 바구니가 차는 걸 보세요. 처음 화면은 ①에서 마지막으로 한 세트 B 입니다.
남은 돈 6원
- 4원
- 3원
- 1원
바구니 0개
- 아직 없음
다음을 눌러 한 줄씩 넘겨 보세요
amount = 6
greedy_coins.py
- 1def greedy_coins(coins, amount):
- 2 coins = sorted(coins, reverse=True)
- 3 given = []
- 4 for coin in coins:
- 5 while amount >= coin:
- 6 amount -= coin
- 7 given.append(coin)
- 8 return given
0 / 15
같은 입력을 모든 경우로 따지면 2개(3 + 3)입니다. 큰 동전부터 준 3개(4 + 1 + 1)보다 적습니다.
sorted(coins, reverse=True)— 동전을 큰 것부터 늘어놓는다while amount >= coin— 남은 돈에 이 동전을 낼 수 있는 동안 계속 낸다amount -= coin— 낼 때마다 남은 돈이 줄어든다. 한 번 낸 동전은 물리지 않는다
동전이 1원·5원·12원일 때, 15원을 큰 동전부터 주면 몇 개일까요?
그리디에서 틀리는 자리
- 정렬을 빼면 —
[1, 3, 4]순서 그대로 6원을 주면 1원부터 줘서 6개가 된다. 큰 동전부터 줄 때는 3개다 - 배수가 아닌 세트에서는 —
[1, 3, 4]6원은 큰 동전부터 3개, 가장 적게는 2개다 - 거슬러 줄 수 없는 돈은 —
[5, 10]으로 12원을 주면 에러 없이[10]이 나오고 남은 2원은 말없이 사라진다. 남은 돈이 0 인지 따로 확인해야 한다 while대신//와%— 세트 A 로 10억 원이면while이 200만 번 돌아 0.04초 걸린다. 몫을amount // coin으로 한 번에 구하면 4번 계산해 0.000003초다(Python 3.14, 컴퓨터마다 다르다)
문제에서 이 말이 보이면
최소 개수큰 것부터 고르면 된다(배수 관계)증명할 수 있으면 그리디, 아니면 DP
다음 장에서는 끝나는 시간이 빠른 회의부터 고르는 회의실 배정을 봅니다.