Minimum Spanning Tree (Kruskal & Prim) — Algoritma

Minimum Spanning Tree (MST) adalah sub-graph tree (tanpa siklus, terhubung) yang mencakup semua node dengan total bobot edge minimum. Analogi: Kamu mau…

Minimum spanning tree (MST) adalah kumpulan edge yang menyambungkan semua node di sebuah graph, tanpa siklus, dengan total bobot paling kecil. Ingat lagi: graph terdiri dari node (titik) dan edge (garis penghubung), bobot adalah biaya sebuah edge, dan siklus adalah jalan yang muter balik ke titik awal. Bayangkan PLN mau menyambungkan listrik ke semua desa dengan total kabel sependek mungkin: jaringan kabel itulah MST-nya.

🧪 Tebakan cepat: sebuah graph punya 5 node. MST-nya selalu punya berapa edge? Tebak dulu, jawabannya ada di bagian "Kruskal: termurah dulu, tolak yang bikin siklus".

Kruskal: termurah dulu, tolak yang bikin siklus

Kruskal mengurutkan semua edge dari bobot terkecil, lalu mengambilnya satu per satu. Edge yang kedua ujungnya sudah tersambung ditolak, karena dia akan bikin siklus. Graph-nya: A-B 4, A-C 2, B-C 1, B-D 5, C-D 8, C-E 10, D-E 2.

Langkah Edge (bobot) Keputusan Kelompok sesudahnya
1 B-C (1) ambil {B, C}, {A}, {D}, {E}
2 A-C (2) ambil {A, B, C}, {D}, {E}
3 D-E (2) ambil {A, B, C}, {D, E}
4 A-B (4) tolak: A dan B sudah satu kelompok sama
5 B-D (5) ambil {A, B, C, D, E}

Totalnya 1 + 2 + 2 + 5 = 10, dengan 4 edge. Semua node sudah satu kelompok, jadi C-D dan C-E gak perlu dicek lagi. Itu jawaban tebakan: graph dengan V node selalu punya MST dengan tepat V - 1 edge. Kurang dari itu, ada node yang belum tersambung. Lebih dari itu, pasti ada siklus.

const edges = [
  ["A", "B", 4],
  ["A", "C", 2],
  ["B", "C", 1],
  ["B", "D", 5],
  ["C", "D", 8],
  ["C", "E", 10],
  ["D", "E", 2],
];

function kruskal(nodes, edges) {
  const parent = {};
  for (const n of nodes) {
    parent[n] = n;
  }

  function find(x) {
    while (parent[x] !== x) {
      x = parent[x];
    }
    return x;
  }

  const terurut = [...edges].sort((a, b) => a[2] - b[2]);
  let total = 0;
  let dipakai = 0;

  for (const [a, b, w] of terurut) {
    const ra = find(a);
    const rb = find(b);
    if (ra === rb) continue; // sudah satu kelompok: siklus

    parent[ra] = rb; // gabungkan dua kelompok
    total += w;
    dipakai++;
    if (dipakai === nodes.length - 1) break;
  }

  return total;
}

console.log(kruskal(["A", "B", "C", "D", "E"], edges)); // 10

Di langkah 4, find("A") jalan A ke C, dan find("B") jalan B ke C. Ketuanya sama-sama C, jadi A-B ditolak.

Kalau node-nya angka

Node juga bisa ditulis sebagai angka 0 sampai n - 1, dengan edge [u, v, weight]. Maka parent cukup berupa array: for (let i = 0; i < n; i++) parent[i] = i;. Sisanya sama persis, dan batasnya n - 1 edge.

Dua kasus kecil ikut beres sendiri. Edge kembar yang menghubungkan pasangan node yang sama ditolak, karena pasangan itu sudah satu kelompok. Graph dengan satu node gak butuh edge apa pun, jadi totalnya 0.

Prim: tumbuh dari satu node

Prim memakai cara lain. Dia mulai dari satu node, misalnya A, lalu tiap langkah mengambil edge termurah yang menyambung pohonnya ke node di luar pohon: A-C 2, lalu C-B 1, lalu B-D 5, lalu D-E 2. Totalnya juga 10. Supaya cepat menemukan edge termurah, Prim biasanya memakai min-heap, struktur yang selalu memberi isi terkecil.

Jadi bedanya: Kruskal mengurutkan semua edge dan memakai union-find, Prim tumbuh dari satu node dengan min-heap. Keduanya greedy (selalu ambil yang termurah saat itu), dan di MST cara greedy ini terbukti selalu benar.

⚠️ Jebakan yang sering ketemu

TL;DR: MST menyambung semua V node tanpa siklus dengan total bobot terkecil, dan selalu punya V - 1 edge. Kruskal: urutkan edge dari bobot terkecil (sort((a, b) => a[2] - b[2])), ambil satu per satu, tolak edge yang kedua ujungnya punya ketua find yang sama, gabungkan dengan parent[ra] = rb, berhenti di V - 1 edge. Prim tumbuh dari satu node dengan min-heap. Hasil totalnya sama.

Yang akan kamu pelajari