오늘은 그리디 알고리즘 문제를 2문제를 풀었습니다. 그럼 어떤 문제인지 살펴볼까요?
인하은행에는 ATM이 1대밖에 없다. 지금 이 ATM앞에 N명의 사람들이 줄을 서있다. 사람은 1번부터 N번까지 번호가 매겨져 있으며, i번 사람이 돈을 인출하는데 걸리는 시간은 Pi분이다.
사람들이 줄을 서는 순서에 따라서, 돈을 인출하는데 필요한 시간의 합이 달라지게 된다. 예를 들어, 총 5명이 있고, P1 = 3, P2 = 1, P3 = 4, P4 = 3, P5 = 2 인 경우를 생각해보자. [1, 2, 3, 4, 5] 순서로 줄을 선다면, 1번 사람은 3분만에 돈을 뽑을 수 있다. 2번 사람은 1번 사람이 돈을 뽑을 때 까지 기다려야 하기 때문에, 3+1 = 4분이 걸리게 된다. 3번 사람은 1번, 2번 사람이 돈을 뽑을 때까지 기다려야 하기 때문에, 총 3+1+4 = 8분이 필요하게 된다. 4번 사람은 3+1+4+3 = 11분, 5번 사람은 3+1+4+3+2 = 13분이 걸리게 된다. 이 경우에 각 사람이 돈을 인출하는데 필요한 시간의 합은 3+4+8+11+13 = 39분이 된다.
줄을 [2, 5, 1, 4, 3] 순서로 줄을 서면, 2번 사람은 1분만에, 5번 사람은 1+2 = 3분, 1번 사람은 1+2+3 = 6분, 4번 사람은 1+2+3+3 = 9분, 3번 사람은 1+2+3+3+4 = 13분이 걸리게 된다. 각 사람이 돈을 인출하는데 필요한 시간의 합은 1+3+6+9+13 = 32분이다. 이 방법보다 더 필요한 시간의 합을 최소로 만들 수는 없다.
줄을 서 있는 사람의 수 N과 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어졌을 때, 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 사람의 수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어진다. (1 ≤ Pi ≤ 1,000)
출력
첫째 줄에 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 출력한다.
예제 입력 1 복사
5
3 1 4 3 2
예제 출력 1 복사
32
ATM이 주어집니다. 사름은 1번부터 N번까지 번호가 매겨져 있으며, i번 사람이 돈을 인출하는데 걸리는 시간은 분입니다.
사람들이 줄을 서는 순서에 따라서, 돈을 인출하는데 필요한 시간의 합이 달라지게 됩니다. 즉, 시간이 누적되어 총 시간이 정해지는 것이죠.
줄을 서 있는 사람의 수 N과 각 사람이 돈을 인출하는데 걸리는 시간 가 주어졌을 때, 각 사람이 돈을 인출하는데 필요한 시간의 합이 최솟값을 구하는 문제입니다.
문제의 입력, 출력을 알아보겠습니다.
그럼 문제를 조금 더 자세하게 분석을 진행해보겠습니다.
이 문제는 일종의 누적합의 최솟값을 구하는 것입니다.
문제의 예시를 보겠습니다.
예를 들어, 총 5명이 있고, P1 = 3, P2 = 1, P3 = 4, P4 = 3, P5 = 2 인 경우를 생각해보자. [1, 2, 3, 4, 5] 순서로 줄을 선다면, 1번 사람은 3분만에 돈을 뽑을 수 있다.
2번 사람은 1번 사람이 돈을 뽑을 때 까지 기다려야 하기 때문에,
3+1 = 4분이 걸리게 된다.
3번 사람은 1번, 2번 사람이 돈을 뽑을 때까지 기다려야 하기 때문에,
총 3+1+4 = 8분이 필요하게 된다.
4번 사람은 3+1+4+3 = 11분, 5번 사람은 3+1+4+3+2 = 13분이 걸리게 된다.
이 경우에 각 사람이 돈을 인출하는데 필요한 시간의 합은 3+4+8+11+13 = 39분이 된다.
줄을 [2, 5, 1, 4, 3] 순서로 줄을 서면, 2번 사람은 1분만에, 5번 사람은 1+2 = 3분,
1번 사람은 1+2+3 = 6분, 4번 사람은 1+2+3+3 = 9분, 3번 사람은 1+2+3+3+4 = 13분이 걸리게 된다.
각 사람이 돈을 인출하는데 필요한 시간의 합은 1+3+6+9+13 = 32분이다.
위 예시의 두 번째 경우를 보면 뭐가 보이시나요? 바로 걸리는 시간이 작은순으로 정렬을 했습니다. 즉, 한 사람이 돈을 인출하는데 걸리는 시간이 작은 사람부터 인출을 시작하면 모든 사람이 돈을 인출하는데 걸리는 시간이 최소라는 것을 알 수 있습니다.
따라서, 정렬과 누적합을 통해 문제를 해결할 수 있습니다.
그러므로 이 문제는 한 사람이 돈을 인출하는데 걸리는 시간이 최솟값이면, 모든 사람이 돈을 인출하는데 걸리는 시간이 최솟값을 보장하는 그리디 알고리즘입니다.
그럼 코드 설계를 진행해보겠습니다.
문제 분석에서 저희는 방법을 거의 다 설계했습니다.
매우 간단합니다!! 바로 코드 구현을 해보겠습니다.
import sys
N = int(sys.stdin.readline().strip())
time = sorted(list(map(int,sys.stdin.readline().split())))
def sol(N,time):
result = 0
for i in range(N):
for j in range(i+1):
result += time[j]
return result
print(sol(N=N,time=time))
코드 설명:
이 코드는 주어진 사람들의 인출 시간을 최소화하기 위해 정렬과 누적합을 이용한 간단한 그리디 알고리즘입니다.
time
을 sorted()
를 이용해 오름차순으로 정렬합니다.for
문을 이용해 첫 번째 사람부터 마지막 사람까지 인출 시간을 계산합니다.result
변수에 각 사람의 인출 누적합을 더해줍니다.for
문에서 i번째 사람까지의 인출 시간을 모두 더하는 방식입니다.result
를 출력하여 최소 인출 시간을 반환합니다.시간 복잡도:
결과:
하지만, 이중 반복문을 사용하지 않고 더 효율적으로 구현할 수 있습니다.
import sys
N = int(sys.stdin.readline().strip())
time = sorted(list(map(int,sys.stdin.readline().split())))
def sol2(N,time):
result = 0
curr = 0
for t in time:
curr += t
result += curr
return result
print(sol2(N=N,time=time))
시간 복잡도:
결과:
이 문제는 그리디 알고리즘의 대표적인 예로, 주어진 조건에서 정렬을 통해 전체 비용을 최소화하는 방식이었습니다. 정렬 이후 누적합 계산 방식을 개선하여 효율성을 높일 수 있었으며, 이를 통해 에서 로 시간 복잡도를 최적화했습니다.
전체 코드는 다음 링크에서 확인할 수 있습니다.
읽어주셔서 감사합니다.
난 할 수 있다!!