🌈 그리디(Greedy)
🔥 그리디(Greedy) 기법 이란?
🔥 그리디(Greedy) 연습 문제
1. 그리디(Greedy) 기법 이란?
- 그리디 알고리즘은 최적의 해에 가까운 값을 구하기 위해 사용되고, 여러 경우 중 하나를 선택할 때마다 매순간 최적이라고 생각되는 경우를 선택하는 방식을 진행하여 최종적인 값을 구하는 방식
- 일반적인 그리디 알고리즘은 문제를 풀기 위한 최소한의 아이디어를 떠올릴 수 있는 능력을 요구함
- 그리디 해법은 그 정당성 분석이 중요함
- 일반적인 상황에서 그리디 알고리즘은 최적의 해를 보장할 수 없을 때가 많음
- 예를들어, 숫자의 합이 가장 큰 경로를 구할 때, 그리디 알고리즘은 단순히 지금 당장 큰 값을 선택하여 경로를 선택하기 때문에 최종적으로 경로의 모든 수의 합이 가장 큰 합이 되지 않을 가능성 존재
- 하지만 코딩 테스트에서의 대부분의 그리디 문제는 탐욕법으로 얻는 해가 최적의 해가 되는 상황을 전제하고, 이를 추론할 수 있어야 풀리도록 문제가 출제됨
1) 거스름 돈 문제
- 거스름돈으로 사용할 수 있는 동전이 500원, 100원, 50원, 10원이 무제한 존재한다고 가정할 때, 거스름돈 N원을 줄 수 있는 최소의 동전을 사용하여 구하시오.
- 최적의 해는 동전의 갯수가 최소가 되야하기 때문에 가장 큰 화폐 단위부터 돈을 거슬러 줘야함
- 즉, N원을 거슬러줘야 할 때, 가장 먼저 500원으로 거슬러 줄 수 있을 만큼 거슬러 준 뒤, 그 후 100원, 50원, 10원을 순으로 최대 거슬러 줘 N값에 도달하는 것이 해법임
coin_list = [100, 10, 50, 500]
def greed_coin_count(money, coin_list):
coin_count = 0
details = list()
coin_list.sort(reverse=True)
for coin in coin_list:
coin_num = money // coin
coin_count += coin_num
money = money % coin
details.append([coin, coin_num])
return coin_count, details
print(greed_coin_count(4720, coin_list))
- 화폐의 종류가 k개 라고 할 때, 시간 복잡도는 O(K)임
- 이 알고리즘의 시간 복잡도는 거슬러줘야 하는 금액과는 무관하며, 동전의 총 종류에만 영향을 받 음
2) 부분 배낭 문제(Fractional Kanpsack Problem)
- 각 물건이 무게(w)와 가치(v)로 표현될 때, 무게 제한이 k인 배낭에 최대 가치를 가지도록 물건을 넣는 문제
def get_max_value(data_list, capacity):
data_list = sorted(data_list, key=lambda x: x[1]/x[0], reverse=True)
total_value = 0
details = list()
for data in data_list:
if capacity - data[0] >= 0:
capacity -= data[0]
total_value += data[1]
details.append([data[0], data[1], 1])
else:
fraction = capacity / data[0]
total_value += data[1] * fraction
details.append([data[0], data[1], fraction])
break
return total_value, details
data_list = [(10,10),(15,12),(20,10),(25,8),(30,5)]
print(get_max_value(data_list, 30))
2. 그리디(Greedy) 연습 문제
1) 1이 될 때까지
- N = 17, K = 4일 때, N이 1이 될 때까지 과정을 수행하는 최소 횟수는 총 3번
- 첫번째(1번 과정) : 17 - 1 = 16
- 두번째(2번 과정) : 16 / 4 = 4
- 세번째(2번 과정) : 4 / 4 = 1
n, k = map(int, input().split())
result = 0
while True:
target = (n // k) * k
result = result + (n - target)
n = target
if n < k:
break
result = result + 1
n = n // k
result = result + (n - 1)
print(result)
n, k = map(int, input().split())
result = 0
while True:
if n % k == 0:
n = n // k
if n < k:
break
else:
if n > k:
target = (n // k) * k
result = result + (n - target)
n = target
else:
result = result + n
result = result + 1
print(result)
2) 곱하기 혹은 더하기
- 대부분의 경우 '+'보다 'x'가 더 값을 크게 만들지만, 두 수 중 1개라도 0 또는 1이였을 때에는 '+'을 수행하는 것이 더 큰 수를 만들 수 있음
- 따라서 두 수에 대하여 연산을 수행할 때, 두 수 중에서 하나라도 1이하인 경우에는 더하고, 두 수가 모두 2이상인 경우에는 곱하면됨
data = input()
result = int(data[0])
for i in range(1, len(data)):
num = int(data[i])
if num <= 1 or result <= 1:
result = result + num
else:
result = result * num
print(result)
3) 모험가 길드
n = int(input())
data = list(map(int, input().split()))
data.sort()
result = 0
count = 0
for i in data:
count = count + 1
if count >= i:
result = result + 1
count = 0
print(result)