일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 알고리즘
- spring security
- 백준
- 프로그래머스
- java
- 소수
- HTTP
- algorithm
- Greedy
- 탐욕법
- error
- beandefinitionstoreexception
- codility
- counting elements
- API
- springboot
- 문자열
- Python
- 라이브템플릿
- 최단경로
- 2981
- applicationeventpublisher
- 2018 KAKAO BLIND RECRUITMENT
- Spring
- BFS
- brute force
- 파이썬
- javascript
- 코딩테스트
- Dijkstra
- Today
- Total
Altiora Petamus
ATM 본문
출처 : https://www.acmicpc.net/problem/11399
탐욕법 (Greedy)
문제
인하은행에는 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)
출력
첫째 줄에 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 출력한다.
예제 입력
5
3 1 4 3 2
예제 출력
32
💡문제풀이
이 문제는 모처럼 짧은 시간인 10분 이내로 푼 것 같다. 코드 및 풀이방법은 다음과 같다.
import sys
n = int(input())
p = list(map(int, input().split()))
p.sort() # 빨리 처리할 수 있는 사람부터 줄 세우기
count = 0 # 시간의 총합
for i in range(n):
for j in range(i+1):
count += p[j]
print(count)
-
먼저 대기시간을 줄이기 위해 걸리는 시간이 짧은 사람부터 오름차순으로 정렬한다.
-
반복문을 돌며 차례대로 count 에 시간을 더하고, 다 돌면 count를 출력한다.
어떠한 예외처리도 없이 단순하게 모두 더하는 방식으로 해결했다.
하지만 이중반복문의 사용은 가급적이면 피하고 싶어서 다른 풀이를 이것저것 확인해봤다. 그러다가 굉장한 풀이방법을 발견해서 공유해본다.
n = int(input())
delay = list(map(int, input().split()))
delay.sort()
sum = 0
for i in range(n):
sum += delay[i] * (n - i)
print(sum)
어떤 로직으로 풀어가야 이런 해법이 나왔을까 고민해봤다. 처음 문제를 풀며 그린 그림을 본 순간 그제서야 원리를 눈치채고 나도 모르게 무릎을 탁...! 치게 되었다.
1
1 + 2
1 + 2 + 3
1 + 2 + 3 + 3
1 + 2 + 3 + 3 + 4
#NOTE: delay[i]가 (n - i)개 만큼 나온다.
세로로 보면 매 루프마다 같은 숫자가 반복되게 된다. 이를 곱셈으로 처리해서 더해주는 로직이였다.
단순히 알고리즘을 파악하고 풀기에는 어렵지 않은 문제였지만 이 코드와 내가 작성했던 코드를 비교해보며 해결과정의 수학적 수준 차이를 알 수 있었다.
이렇게 오늘도 더욱 열심히 공부해야하는 이유를 찾았습니다.
'1day-1algorithm' 카테고리의 다른 글
로프 (0) | 2021.02.23 |
---|---|
동전 0 (0) | 2021.02.20 |
설탕 배달 (0) | 2021.02.19 |
구명보트 (0) | 2021.02.17 |
두 개 뽑아서 더 하기 (프로그래머스) (0) | 2021.02.16 |