처음에는 O(N)인 우선순위 큐를 만들어 돌렸으나 시간초과가 났다..
class priorityQueue {
constructor() {
this.queue = [];
}
enQueue(elements) {
let queueChange = false;
for (let i = 0; i < this.queue.length; i++) {
if (this.queue[i][0] > elements[0]) {
this.queue.splice(i, 0, elements);
queueChange = true;
break;
}
}
if (queueChange === false) {
this.queue.push(elements);
}
}
deQueue() {
return !this.isEmpty() && this.queue.shift();
}
isEmpty() {
return this.queue.length <= 0;
}
}
검색해보니 O(log n)인 우선순위큐를 찾았다.
우선순위큐에 관해서는 다른 글에서 따로 다루겠습니다 😀
class Heap {
constructor(comparator = (a, b) => a - b) {
this.array = [];
this.comparator = (i1, i2) => {
const value = comparator(this.array[i1], this.array[i2]);
if (Number.isNaN(value)) {
throw new Error(
`Comparator should evaluate to a number. Got ${value} when comparing ${this.array[i1]} with ${this.array[i2]}`
);
}
return value;
};
}
/**
* Insert element
* @runtime O(log n)
* @param {any} value
*/
add(value) {
this.array.push(value);
this.bubbleUp();
}
/**
* Retrieves, but does not remove, the head of this heap
* @runtime O(1)
*/
peek() {
return this.array[0];
}
/**
* Retrieves and removes the head of this heap, or returns null if this heap is empty.
* @runtime O(log n)
*/
remove(index = 0) {
if (!this.size) return null;
this.swap(index, this.size - 1); // swap with last
const value = this.array.pop(); // remove element
this.bubbleDown(index);
return value;
}
/**
* Returns the number of elements in this collection.
* @runtime O(1)
*/
get size() {
return this.array.length;
}
/**
* Move new element upwards on the heap, if it's out of order
* @runtime O(log n)
*/
bubbleUp() {
let index = this.size - 1;
const parent = (i) => Math.ceil(i / 2 - 1);
while (parent(index) >= 0 && this.comparator(parent(index), index) > 0) {
this.swap(parent(index), index);
index = parent(index);
}
}
/**
* After removal, moves element downwards on the heap, if it's out of order
* @runtime O(log n)
*/
bubbleDown(index = 0) {
let curr = index;
const left = (i) => 2 * i + 1;
const right = (i) => 2 * i + 2;
const getTopChild = (i) =>
right(i) < this.size && this.comparator(left(i), right(i)) > 0
? right(i)
: left(i);
while (
left(curr) < this.size &&
this.comparator(curr, getTopChild(curr)) > 0
) {
const next = getTopChild(curr);
this.swap(curr, next);
curr = next;
}
}
/**
* Swap elements on the heap
* @runtime O(1)
* @param {number} i1 index 1
* @param {number} i2 index 2
*/
swap(i1, i2) {
[this.array[i1], this.array[i2]] = [this.array[i2], this.array[i1]];
}
}
아래는 우선순위 큐로 다익스트라를 구현한 풀이 답안이다.
const fs = require("fs");
const stdin = (
process.platform === "linux"
? fs.readFileSync("/dev/stdin").toString()
: `5
8
1 2 2
1 3 3
1 4 1
1 5 10
2 4 2
3 4 1
3 5 1
4 5 3
1 5`
).split("\n");
const input = (() => {
let line = 0;
return () => stdin[line++];
})();
const N = +input();
const M = +input();
const arr = Array.from({ length: N + 1 }, () => []);
for (let i = 0; i < M; i++) {
const [a, b, c] = input()
.trim()
.split(" ")
.map((v) => +v);
arr[a].push([c, b]);
}
class Heap {
constructor(comparator = (a, b) => a - b) {
this.array = [];
this.comparator = (i1, i2) => {
const value = comparator(this.array[i1], this.array[i2]);
if (Number.isNaN(value)) {
throw new Error(
`Comparator should evaluate to a number. Got ${value} when comparing ${this.array[i1]} with ${this.array[i2]}`
);
}
return value;
};
}
/**
* Insert element
* @runtime O(log n)
* @param {any} value
*/
add(value) {
this.array.push(value);
this.bubbleUp();
}
/**
* Retrieves, but does not remove, the head of this heap
* @runtime O(1)
*/
peek() {
return this.array[0];
}
/**
* Retrieves and removes the head of this heap, or returns null if this heap is empty.
* @runtime O(log n)
*/
remove(index = 0) {
if (!this.size) return null;
this.swap(index, this.size - 1); // swap with last
const value = this.array.pop(); // remove element
this.bubbleDown(index);
return value;
}
/**
* Returns the number of elements in this collection.
* @runtime O(1)
*/
get size() {
return this.array.length;
}
/**
* Move new element upwards on the heap, if it's out of order
* @runtime O(log n)
*/
bubbleUp() {
let index = this.size - 1;
const parent = (i) => Math.ceil(i / 2 - 1);
while (parent(index) >= 0 && this.comparator(parent(index), index) > 0) {
this.swap(parent(index), index);
index = parent(index);
}
}
/**
* After removal, moves element downwards on the heap, if it's out of order
* @runtime O(log n)
*/
bubbleDown(index = 0) {
let curr = index;
const left = (i) => 2 * i + 1;
const right = (i) => 2 * i + 2;
const getTopChild = (i) =>
right(i) < this.size && this.comparator(left(i), right(i)) > 0
? right(i)
: left(i);
while (
left(curr) < this.size &&
this.comparator(curr, getTopChild(curr)) > 0
) {
const next = getTopChild(curr);
this.swap(curr, next);
curr = next;
}
}
/**
* Swap elements on the heap
* @runtime O(1)
* @param {number} i1 index 1
* @param {number} i2 index 2
*/
swap(i1, i2) {
[this.array[i1], this.array[i2]] = [this.array[i2], this.array[i1]];
}
}
const pq = new Heap((a, b) => a[0] - b[0]);
const dijkstra = (start) => {
const dp = new Array(N + 1).fill(Infinity);
dp[start] = 0;
pq.add([0, start]);
while (pq.size > 0) {
const [pqW, pqV] = pq.remove();
if (dp[pqV] < pqW) continue;
for (let [arrW, arrV] of arr[pqV]) {
const totalW = arrW + pqW;
if (totalW < dp[arrV]) {
dp[arrV] = totalW;
pq.add([totalW, arrV]);
}
}
}
return dp;
};
const [start, destination] = input()
.trim()
.split(" ")
.map((v) => +v);
const result = dijkstra(start);
console.log(result[destination]);
반응형
'Algorithm > 백준' 카테고리의 다른 글
백준 1253번 좋다 python (0) | 2022.07.01 |
---|---|
백준 도서관 1461 python (0) | 2022.06.30 |
콘센트 23843 python (0) | 2022.06.29 |
특정한 최단 경로 1504 javascript (0) | 2022.06.29 |
Puyo Puyo (0) | 2022.06.22 |
댓글