
간략하게 문제는 다음과 같다.
ex) 예를 들어 10장, 20장, 40장의 묶음이 있다면 10장과 20장을 합친 뒤, 합친 30장 묶음과 40장을 합친다면 (10 + 20) + (30 + 40) = 100번의 비교가 필요하다. 그러나 10장과 40장을 합친 뒤, 합친 50장 묶음과 20장을 합친다면 (10 + 40) + (50 + 20) = 120 번의 비교가 필요하므로 덜 효율적인 방법이다.
N 개의 카드가 첫줄, 그 뒤에는 카드 묶음의 크기가 주어진다.가장 작은 경우는 작은 묶음 2개를 골라서 지속 적으로 더하는 방법이 가장 적을 것이다.
그 이유는 A, B, C, D 뭉치가 있고 순서대로 카드를 합쳐 준다고 했을 때, +를 더해주는 횟수로 계산하면
| A+B | (A+B) + C | (A+B+C)+ D | |
|---|---|---|---|
| A | + | + + | + + + |
| B | + | + + | + + + |
| C | + | + + | |
| D | + |
다음과 같기 때문에 A,B,C,D 는 작은 숫자 순으로 정렬되어야 한다.
따라서 위의 문제는 우선순위 큐(Priority Queue) 문제이고 풀이 과정은 다음과 같다.
PQ에 값을 모두 넣는다. PQ에서 값을 두개씩 꺼내서 더한 후 그 값을result 변수에 넣는다.answer 에 result를 더한 후 PQ에 다시 result 값을 넣는다.PQ 에 한개의 변수만 들어있을 때까지 반복우선순위 큐(Priority Queue) 구현에 대한 설명은 링크에서 참고
전체 코드
let fs = require("fs");
let input = fs.readFileSync("/dev/stdin").toString().trim().split("\n").map(Number);
let N = input.shift();
class MinHeap {
constructor() {
this.heap = [null];
}
insert(element) {
let current = this.heap.length;
while (current > 1) {
const parent = Math.floor(current / 2);
if (this.heap[parent] > element) {
this.heap[current] = this.heap[parent];
current = parent;
}else break;
}
this.heap[current] = element;
}
remove() {
let top = this.heap[1];
if (this.heap.length > 2) {
this.heap[1] = this.heap.pop();
let current = 1;
let leftChild = current * 2;
let rightChild = current * 2 + 1;
while (this.heap[leftChild]) {
let CompareChild = leftChild;
if (this.heap[rightChild] && this.heap[leftChild] > this.heap[rightChild]) {
CompareChild = rightChild;
}
if (this.heap[CompareChild] < this.heap[current]) {
const temp = this.heap[current];
this.heap[current] = this.heap[CompareChild];
this.heap[CompareChild] = temp;
current = CompareChild;
}else break;
leftChild = current * 2;
rightChild = current * 2 + 1;
}
}else if (this.heap.length === 2) {
this.heap.pop();
}else{
return 0;
}
return top;
}
getSize() {
return this.heap.length - 1;
}
getHeap() {
return this.heap;
}
}
const PQ = new MinHeap();
for (const number of input) {
PQ.insert(number);
}
let answer = 0;
while (PQ.getSize()) {
if (PQ.getSize() > 1){
const first = PQ.remove();
const second = PQ.remove();
const result = first + second;
answer += result;
PQ.insert(result);
}else break;
}
console.log(answer);
최소힙의 응용 문제였다.
최근들어 최소힙과 우선순위 큐 문제를 집중적으로 풀고 있는데 이제 최소힙을 직접 구현하는 것도 조금씩 익숙해 지는 것 같다.