1. 문제요약
각 묶음의 카드의 개수가 A, B 라고 주어질 때, 한 번 두 묶음을 합칠 때 A+B 번의 비교를 해야한다. 만약 A, B, C, D 의 카드 개수를 순서대로 하나로 합치려고 할 때, (A+B) + ((A+B)+C) + ((A+B+C)+D) 번 총 비교해야 한다.
카드의 개수가 연속으로 주어질 때, 최소한 몇 번 비교해야 하는지 알아내시오.
2. 문제예제
3. 문제풀이(수동)
주어진 문제예제를 살펴보면, (10+20) 번 비교하고, 다시 그 묶음을 40 번과 비교해서 (10+20) + (30+40) 번 비교해야 한다. 정렬이 되어 있지 않는 경우도 살펴볼 수 있다. 10, 20, 28, 25 라면, (10+20) 번 비교하고, (28+25) 번 비교한 다음 두 카드비교를 더해 (10+20) + (28+25) + (10+20) + (28+25) 로 최소 166 번 비교할 수도 있다.
4. 팩트추출
Fact 1 : 한 번 합쳐진 값도 다시 하나의 값으로 인식해서 나머지 다른 값들과 비교해 최소끼리 계속 더해야 한다.
문제풀이(수동) 두 번째 예제를 보면 10+20 번 비교해서 한 번 합쳐진 값이 다른 값들과 비교하는데 나머지 25, 28 숫자보다 커서 25와 28끼리 합쳐야 한 것을 볼 수 있다.
Fact 2 : Fact 1 번을 통해 연산한 결과 값들도 나머지 다른 값들과 함께 정렬되어 다시 연산에 쓰여야 된다는 것을 알 수 있다. 다시 말해보면, 삽입하면서 정렬이 되고 그 중 항상 최소값을 가져와야 한다.
5. 문제전략
Fact 2 번을 통해 연산한 결과 값이 삽입하면서 정렬이 되어야 하고, 항상 최소값을 가져와야 한다는 점 때문에 우선순위 큐를 사용하면 된다.
5. 소스코드
import java.io.*;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int N = Integer.parseInt(br.readLine());
long total = 0;
PriorityQueue<Long> pq = new PriorityQueue<>();
for (int i = 0; i < N; i++) {
long cardValue = Long.parseLong(br.readLine());
pq.add(cardValue);
}
while (pq.size() > 1) {
long first = pq.poll();
long second = pq.poll();
total += first + second;
pq.add(first + second);
}
System.out.println(total);
}
}
'알고리즘 > BOJ' 카테고리의 다른 글
[BOJ] 13334 철로 (Java) (1) | 2023.11.12 |
---|---|
[BOJ] 24042 횡단보도 (Java) (0) | 2022.10.12 |
[BOJ] 10830 행렬 제곱 (Java) (0) | 2022.10.03 |
[BOJ] 9376 탈옥 (Java) (0) | 2022.10.02 |
[BOJ] 이항 계수 (Java) (0) | 2022.09.29 |