- 현재 상황에서 가장 좋아보이는 것만 선택하는 알고리즘
- 그리디 알고리즘의 정당성을 고민하면서 문제 해결 방안을 떠올려야 한다.
- 단순히 가장 좋아 보이는 것을 반복적으로 선택해도 최적 해를 구할 수 있는지를 검토 !!
- 최적해를 보장할 수 없을 때가 많다. 하지만, 코테는 탐욕법으로 얻은해가 최적해가 되는 상황에서 이를 추론할 수 있는지를 확인한다.
거스름돈
n = 1260
count = 0
array = [500, 100, 50, 10]
for coin in array:
count += n // coin
n %= coin
print(count)
- Time Complexity : O(K) => 화폐 총 종류만 영향을 미침
- 거스름돈: 정당성 분석 예제에서 가장 큰 화폐 단위부터 돈을 거슬러주는 것이 최적해를 보장하는 이유는 ?
- 가지고 있는 동전 중 큰 단위가 항상 작은 단위의 배수이기 때문에 작은 단위 동전들을 종합해 다른 해가 나올 수 없기 때문이다.
- 800원을 거슬러 주기 위해 화폐 단위가 500, 400, 100 이라면 400원 2개를 거슬러주는 것이 최적해인데, 500원부터 거슬러주면 500원 1개, 100원 3개인 총 4개를 거슬러줘야 된다. 큰 단위 화폐가 작은 단위 화폐의 배수가 아니기 때문에 그리디 알고리즘이 최적해를 갖지 못하는 것이다.
- 그리디 알고리즘은 최소한의 아이디어를 떠올리고 이것이 정당한가?를 검토할 수 있어야한다.
1이 될 때까지
n, k = map(int, input().split())
result = 0
while True:
target = (n // k) * k
result += (n - target)
n = target
if n < k:
break
result += 1
n //= k
result += (n-1)
print(result)
- n, k가 매우 큰 수더라도 빠르게 처리할 수 있다.
Ex1) 모험가 길드
n = int(input())
data = list(map(int, input().split(' ')))
data.sort()
count = 0
result = 0
for i in data:
count += 1
if count >= i:
result += 1
count = 0
print(result)
Ex2) 곱하기 혹은 더하기
n = input()
result = ''
for number in n:
result += number
if number == '0':
result += '+'
else:
result += '*'
result = eval(result[:-1])
print(result)
Reference
data = input()
result = int(data[0])
for i in range(1, len(data)):
num = int(data[i])
if num <= 1 or result <= 1:
result += num
else:
result *= num
print(result)
Ex3)문자열 뒤집기
n = input()
count_0 = 0
count_1 = 0
prev = n[0]
for i in range(1, len(n)):
if n[i] == prev and n[i] == '0':
count_0 += 1
elif n[i] == prev and n[i] == '1':
count_1 += 1
prev = n[i]
result = min(count_0, count_1)
print(result)
Reference
data = input()
count0 = 0
count1 = 0
if data[0] == '1':
count0 += 1
else:
count1 += 1
for i in range(len(data) - 1):
if data[i] != data[i + 1]:
if data[i + 1] == '1':
count0 += 1
else:
count1 += 1
print(min(count0, count1))
- 좀 더 세련된 코드 같다.
- index만 사용해서 Space Complexity가 더 적다.
Ex4) 만들 수 없는 금액
Reference
N = 5
data = [3, 2, 1, 1, 9]
data.sort()
target = 1
for i in data:
if target < i:
break
target += i
print(target)
- 정렬을 이용한 그리디 알고리즘
- 현재 상태를 1 ~ target - 1 까지 모든 금액을 만들 수 있다고 가정한다.
- 화폐 단위가 작은 순서대로 동전을 확인하며 현재 확인하는 동전으로 target 금액을 만들 수 있는지 확인한다.
- 만들 수 있다면 target을 update 한다. 만들 수 있다는 뜻은 현재 확인하는 coin의 화폐가 target이하 라는 뜻이다.
Ex5) 볼링공 고르기
Reference
N, M = list(map(int, input().split()))
data = list(map(int, input().split()))
array = [0] * 11
for x in data:
array[x] += 1
result = 0
for i in range(1, M+1):
N -= array[i]
result += array[i] * N
print(result)
- array를 통해 해당 번호의 개수를 세어 준다.
- A, B 두 사람이 고른다고 하면, Step이 진행 되면서 B가 선택하는 경우는 줄어든다. 이미 계산했던 경우는 제외하기 때문이다. (조합)