일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- 프로그래머스
- 99클럽
- DP
- 백트래킹
- 스프링
- 항해99
- 완전탐색
- lower bound
- 백준
- 네트워크 계층
- 자바
- Til
- 알고리즘
- 그리디
- 그래프
- 트리
- 동적 프로그래밍
- BinarySearch
- Java
- 데이터베이스
- BFS
- 우선순위큐
- 브루트포스
- 그래프 이론
- 정렬
- 코딩테스트준비
- 스프링 핵심 원리 - 기본편
- 개발자취업
- DFS
- Today
- Total
AtraFelis's Develop Diary
[99클럽 코테스터디 17일차 TIL / 백준] 11399 - ATM (그리디, 정렬) 본문
99클럽 코테스터디 17일차 TIL
KeyWord : 그리디, 정렬
문제
인하은행에는 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)
출력
첫째 줄에 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 출력한다.
풀이
매우 간단한 그리디 문제이다. 지문은 길지만, 문제를 이해했다면 해결 방법은 쉽게 떠올릴 수 있었을 것이라 생각한다.
배열이 주어지고, 이 배열의 원소들을 여러 방식으로 배치하여 누적합의 최솟값을 구하는 문제라고 생각해도 된다.
일단 N=5로 들어오는 입력에 아무것도 하지 않고 누적합을 구해보자.
$P1 + P1 + P2 + P1 + P2 + P3 + P1 + P2 + P3 + P4 + P1 + P2 + P3 + P4 + P5$
식을 쭉 나열하면 이렇게 된다. 이 식을 간단하게 정리하면, $5P_1 + 4P_2 + 3P_3 + 2P_4 + P_5$ 이렇게 된다. 즉, $P_1 < P_2 < P_3 < P_4 < P_5$ 순서대로 수가 배열이 되어야 누적합이 최소가 된다는 것을 알 수 있다.
여기까지 왔으면, 로직은 쉽게 만들 수 있다.
- 입력되는 배열을 오른차순으로 정렬
- 배열의 누적합을 구한다.
풀이
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[] people = new int[N];
StringTokenizer stk = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
people[i] = Integer.parseInt(stk.nextToken());
}
Arrays.sort(people);
int ans = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
ans += people[j];
}
}
System.out.println(ans);
}
}
여담 : 누적합에서 효율성 챙기기
이 문제의 경우에는 이 부분에서 효율성 체크를 안 하기에 상관 없지만, 그래도 알아두면 좋으므로 적어두려고 한다.
int ans = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
ans += people[j];
}
}
위 코드를 보면 이렇게 누적합을 구하는 것을 볼 수 있다. 하지만 이렇게 누적합을 구현하면, 이중 루프로 인하여 $O(N^2)$의 비효율적인 시간복잡도가 된다.
int[] prefixSum = new int[N];
prefixSum[0] = people[0];
for (int i = 1; i < N; i++) {
prefixSum[i] = people[i] + prefixSum[i-1];
}
for (int i = 0; i < N; i++) {
ans += prefixSum[i];
}
하지만 이렇게 또 하나의 배열을 이용하여 각 인덱스별 누적합을 미리 구한 후, 마지막에 한 번에 합하는 방식으로 수정을 하면 $O(N)$의 시간 복잡도로 효율성을 챙길 수 있다.
References
'Algorithm > 백준' 카테고리의 다른 글
[99클럽 코테스터디 19일차 TIL / 백준] 1945 - 신입 사원 (그리디, 정렬) (0) | 2025.02.13 |
---|---|
[99클럽 코테스터디 18일차 TIL / 백준] 17503 - 맥주 축제 (그리디, 정렬, 우선순위큐) (0) | 2025.02.12 |
[99클럽 코테스터디 16일차 TIL / 백준] 27961 - 고양이는 많을 수록 좋다 (그리디) (0) | 2025.02.10 |
[99클럽 코테 스터디 15일차 TIL / 백준] 15685 - 치킨 배달 (브루트포스, 백트래킹) (0) | 2025.02.07 |
[99클럽 코테 스터디 14일차 TIL / 백준] 2615 - 오목 (브루트포스) (0) | 2025.02.06 |