์ต๋จ๊ฒฝ๋ก ์๊ณ ๋ฆฌ์ฆ
Unweighted graph (BFS)
๋๋น ์ฐ์ ํ์ BFS ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ค.
๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ์์ ์์์ ์์ ๋ชฉํ์ ๊น์ง์ ์ต๋จ ๊ฒฝ๋ก๋ ๊ฐ์ฅ ์ ์ ์์ ๊ฐ์ ์ ๊ฐ์ง๋ ๊ฒฝ๋ก๋ฅผ ์๋ฏธํ๋ค.
BFS์๊ณ ๋ฆฌ์ฆ์ ๋ณต์กํ๊ฒ ์ฝํ์๋ ๊ทธ๋ํ๋ฅผ ์์์ ์ ๋ฃจํธ๋ก ํ๋ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ์ฌ๊ตฌ์ฑ์ ํ๋๊ฒ๊ณผ ๋น์ทํ๋ค(๊ณ ์๊ฐํ๋ค).
๊ทธ๋์ ๋ชฉ์ ์ง ๋
ธ๋๊ฐ ์ํ ๋ ๋ฒจ์ ๊ตฌํ๋ฉด ๊ทธ๊ฒ ๊ณง ์ต๋จ ๊ฑฐ๋ฆฌ๊ฐ ๋๊ณ ํด๋น ๊ฒฝ๋ก ์์ ๊ฐ์ ๋ค์ ๋ชจ์์ด ์ต๋จ๊ฒฝ๋ก๊ฐ ๋๋ค.
์ฌ๊ฑด ๋ณต์ก๋๋ O(V+E).
function bfsShortestPath(graph, start, end) {
const queue = [[start, [start]]];
const visited = new Set([start]);
while (queue.length > 0) {
const [node, path] = queue.shift();
if (node === end) {
return path;
}
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
queue.push([neighbor, [...path, neighbor]]);
}
}
}
return null;
}
const graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'D'],
'D': ['B', 'C', 'F'],
'E': ['B', 'F'],
'F': ['D', 'E']
};
console.log(bfsShortestPath(graph, 'A', 'F'));
Weighted graph (๋ค์ต์คํธ๋ผ)
Dijkstra์ ์ํด ๊ณ ์๋ ์๊ณ ๋ฆฌ์ฆ.
๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ์ BFS์๊ณ ๋ฆฌ์ฆ์ ์ผ๋ฐํํ ๊ฒ์ด๋ค. (์ '์ผ๋ฐํ'๋ผ๊ณ ํ๋๋ฉด, unweighted graph๋ ๋ชจ๋ ๊ฐ์ ์ ๊ฐ์ค์น๊ฐ 1๋ก ๋์ผํ ๋งค์ฐ ํน์ํ weighted graph์ด๊ธฐ ๋๋ฌธ์.)
class MinHeap {
constructor() {
this.heap = [];
}
push(val) {
this.heap.push(val);
this._heapifyUp(this.heap.length - 1);
}
pop() {
if (this.size() === 0) return null;
if (this.size() === 1) return this.heap.pop();
const min = this.heap[0];
this.heap[0] = this.heap.pop();
this._heapifyDown(0);
return min;
}
size() {
return this.heap.length;
}
_heapifyUp(index) {
while (index > 0) {
const parent = Math.floor((index - 1) / 2);
if (this.heap[parent][0] <= this.heap[index][0]) break;
[this.heap[parent], this.heap[index]] = [this.heap[index],
this.heap[parent]];
index = parent;
}
}
_heapifyDown(index) {
const n = this.heap.length;
while (true) {
let smallest = index;
const left = 2 * index + 1;
const right = 2 * index + 2;
if (left < n && this.heap[left][0] < this.heap[smallest][0]){
smallest = left;
}
if (right < n && this.heap[right][0] < this.heap[smallest][0]){
smallest = right;
}
if (smallest === index) break;
[this.heap[smallest], this.heap[index]] =
[this.heap[index], this.heap[smallest]];
index = smallest;
}
}
}
// Function to construct adjacency
function constructAdj(edges, V) {
// adj[u] = list of [v, wt]
const adj = Array.from({ length: V }, () => []);
// const adj = Array(V).fill().map(()=>[]); ์ ๊ฐ์ ์ฝ๋
for (const edge of edges) {
const [u, v, wt] = edge;
adj[u].push([v, wt]);
adj[v].push([u, wt]);
}
return adj;
}
// Returns shortest distances from src to all other vertices
function dijkstra(V, edges, src, target) {
const adj = constructAdj(edges, V);
const minHeap = new MinHeap();
const dist = Array(V).fill(Number.MAX_SAFE_INTEGER);
const parent = Array(V).fill(-1); // ๋ถ๋ชจ ๋
ธ๋ ์ถ์ ์ฉ
minHeap.push([0, src]);
dist[src] = 0;
while (minHeap.size() > 0) {
const [d, u] = minHeap.pop();
// ๋ชฉํ ๋
ธ๋์ ๋๋ฌํ๋ฉด ์กฐ๊ธฐ ์ข
๋ฃ ๊ฐ๋ฅ
if (u === target) break;
// ์ด๋ฏธ ์ฒ๋ฆฌ๋ ๋
ธ๋๋ผ๋ฉด ์คํต
if (d > dist[u]) continue;
for (const [v, weight] of adj[u]) {
if (dist[v] > dist[u] + weight) {
dist[v] = dist[u] + weight;
parent[v] = u; // v์ ๋ถ๋ชจ๋ฅผ u๋ก ์ค์
minHeap.push([dist[v], v]);
}
}
}
// ๊ฒฝ๋ก ๋ณต์
const path = [];
let current = target;
if (dist[target] === Number.MAX_SAFE_INTEGER) {
return { distance: -1, path: [] }; // ๋๋ฌ ๋ถ๊ฐ๋ฅ
}
while (current !== -1) {
path.unshift(current);
current = parent[current];
}
return { distance: dist[target], path: path };
}
// Driver code
const V = 5;
// edge list format: [u, v, weight]
const edges = [[0, 1, 4], [0, 2, 8], [1, 4, 6], [2, 3, 2], [3, 4, 10]];
const result = dijkstra(V, edges, 0, 3);
// Print shortest distances in one line
console.log(`Distance: ${result.distance}`);
console.log(`Path: ${result.path.join(' -> ')}`);
Minimum Spanning Tree
Spanning Tree ๋ ์ด๋ค ๊ทธ๋ํ์ spanning tree๋ ์ด๋ค ๊ทธ๋ํ์ ๋ชจ๋ ์ ์ ์ ํฌํจํ๊ณ ์๋ sub-graph์ด๋ฉด์ ๋ํ tree์ด๋ค.
ํ ๊ทธ๋ํ์๋ ์ฌ๋ฌ ์คํจ๋ ํธ๋ฆฌ๊ฐ ์์ ์ ์๋ค.
๋น์ฐํ ์์ ์๋ ์๋ค. ์ฐ๊ฒฐ๋์ง ์์ ๋
ธ๋๊ฐ ์๋ disconnected graph์๋ ์คํจ๋ ํธ๋ฆฌ๊ฐ ์กด์ฌํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ Minimum Spanning Tree๋ ๊ฒฝ๋ก๋ค์ ๊ฐ์ค์น์ ํฉ์ด ๊ฐ์ฅ ๋ฎ์ผ๋ฉด์ ๊ทธ๋ํ์ ๋ชจ๋ ์ ์ ์ ํฌํจํ๊ณ ์๋ ํธ๋ฆฌ๋ค.
ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ Kruskal Algorithm
ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๋จํ ์ค๋ช ํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- ๋ชจ๋ ์ฃ์ง๋ค์ ๊ฐ์ค์น ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ
- ์์ ์์๋๋ก ํ์ธํด๋ณด๋ฉด์ ํด๋น ์ฃ์ง๊ฐ ์ฌ์ดํด์ ๋ฐ์์ํค๋์ง ํ์ธ
- ๋ฐ์์ํค์ง ์๋๋ค๋ฉด ์ถ๊ฐํ๋ค.
function kruskalsMST(V, edges) {
// Sort all edges
edges.sort((a, b) => a[2] - b[2]);
// Traverse edges in sorted order
const dsu = new DSU(V);
let cost = 0;
let count = 0;
for (const [x, y, w] of edges) {
// Make sure that there is no cycle
if (dsu.find(x) !== dsu.find(y)) {
dsu.unite(x, y);
cost += w;
if (++count === V - 1) break;
}
}
return cost;
}
// Disjoint set data structure
class DSU {
constructor(n) {
this.parent = Array.from({ length: n }, (_, i) => i);
this.rank = Array(n).fill(1);
}
find(i) {
if (this.parent[i] !== i) {
this.parent[i] = this.find(this.parent[i]);
}
return this.parent[i];
}
unite(x, y) {
const s1 = this.find(x);
const s2 = this.find(y);
if (s1 !== s2) {
if (this.rank[s1] < this.rank[s2]) this.parent[s1] = s2;
else if (this.rank[s1] > this.rank[s2]) this.parent[s2] = s1;
else {
this.parent[s2] = s1;
this.rank[s1]++;
}
}
}
}
const edges = [
[0, 1, 10], [1, 3, 15], [2, 3, 4], [2, 0, 6], [0, 3, 5]
];
console.log(kruskalsMST(4, edges));
๊ฒฐ๊ตญ ํต์ฌ์ ํด๋น ์ฃ์ง๊ฐ ์ฌ์ดํด์ ๋ง๋ค์ด๋ด๋์ง ๊ฒ์ฌํ๋ ๊ณผ์ ์ ์๋๋ค.
์์
์์๋ ์ง์ ์งํฉ์ ๋ง๋ค์ด๊ฐ๋ฉด์ ์์๋ฅผ ๋ณด์๋๋ฐ (๊ทธ๋์ ์ดํดํ๊ธฐ๊ฐ ์ฌ์ ๋๋ฐ), ์์์๋ ์ง์ ์งํฉ์ ๋ง๋๋ ๋ฐฉ์ ๋์ parent
์ rank
๋ฐฐ์ด์ ๋ง๋ค์ด์ ์ฌ์ฉํ๋ค.
์ด๋ป๊ฒ ์์ ์ฝ๋๊ฐ ๋์ผํ ๊ฒฐ๊ณผ๋ฌผ์ ๋ด๋๋๋ก ์์ฉํ๋์ง ์ดํด๋ณด์.
parent
๋ฐฐ์ด์ ๊ฐ ๋ ธ๋๋ค์ด ์์ ์ด ์ด๋ ๋ ธ๋์ ์งํฉ์ ์ํด์๋์ง ๋ํ๋ธ๋ค.[0,1,2,3]
์์[0,1,2,2]
๊ฐ ๋๋ฉด 3๋ฒ์ด 2๋ฒ ๋ ธํธ์ ์งํฉ์ ๋ค์ด๊ฐ๋ค๋ ๋ป.unite()
ํจ์๋ ๋ ๋ ธ๋์ ์งํฉ์ค์ rank๊ฐ ๋ฎ์ ์ชฝ์ ๋์ ์ชฝ์ ํฉ์น๋ค.
์ด๋ ๊ฒ ํ๋ ์ด์ ๋ (๋น์ฐํ๊ฒ๋) ์ด ๋ฐฉ๋ฒ์ด ํจ์ฌ ํจ์จ์ ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด O(1)์ ์๋๋ก ์งํฉ์ ํฉ์น๋ ํจ๊ณผ๋ฅผ ๋ผ ์ ์๊ธฐ ๋๋ฌธ์. (๋ฐ๋ฉด์ ๊ณต๊ฐ ๋ณต์ก๋๋ ๋ ๋ง์ด ์ฌ์ฉํ๋ค๊ณ ํ๋ค.)
์๊ฐ๋ณต์ก๋
๋ฐฉ๊ธ ์์๋ณธ ๋ฐฉ๋ฒ์ ํตํด์ find()
์ unite()
ํจ์๋ ๋ชจ๋ O(1) ์ ์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค๋๊ฒ์ ํ์ธํ๋ค. ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ ์์ฒด๊ฐ ์ ๋ ฌ + union/find ์ด๊ธฐ ๋๋ฌธ์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๊ฐ ๊ณง ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ๋ณต์ก๋๊ฐ ๋๋ค.
ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ Prim Algorithm
ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ์ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ํก์ฌํ๋ค. ํ๋์ ๋ ธ๋์์ ์์ํด์ ๊ทธ๋๋ง๋ค ๊ฐ์ค์น๊ฐ ์ ์ ์ฃ์ง์ ์ฐ๊ฒฐ๋ ๋ ธ๋๋ฅผ ๊ณ์ํด์ ์ถ๊ฐํด๋๊ฐ๋ ๊ฒ.
๋ค๋ฅธ ์ ์ ๊ฑฐ๋ฆฌ์ ๋ํ ์ ์๊ฐ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๋ค๋ฅด๋ค๋ ์ .
- ๋ค์ต์คํธ๋ผ์์์ ๊ฑฐ๋ฆฌ : ์์์ ์์ ๋ชฉํ ๋ ธ๋๊น์ง์ ์ต๋จ๊ฒฝ๋ก ์ดํฉ.
- ํ๋ฆผ์์์ ๊ฑฐ๋ฆฌ : ํ์ฌ MST์์ ํด๋น ๋ ธ๋๊น์ง์ ์ต์ ๊ฐ์ ๊ฐ์ค์น.
์ฌ์ดํด?
์ฌ์ดํด์ ์ด๋ฏธ ์ฐ๊ฒฐ๋์ด์๋ ๋ ธ๋๋ค ์ฌ์ด์ ์ฃ์ง๊ฐ ์ถ๊ฐ๋๋๊ฒ์ธ๋ฐ, ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ์์๋ ํญ์ MST ๋ฐ์ ๋ ธ๋๋ฅผ ์ถ๊ฐํด๋๊ฐ๊ธฐ ๋๋ฌธ์ ์ฌ์ดํด์ด ๋ฐ์ํ ์ ์๋ค.
์๊ฐ๋ณต์ก๋
ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ์ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ์๋ ๋ฐฉ์์ด ๋๊ฐ๊ธฐ ๋๋ฌธ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ฐ์ ์ ๋ฐ์ ์๋ค.