Skip to main content

Minimum Spanning Tree

Minimum Spanning Tree คืออะไร

Minimum Spanning Tree (MST) หรือ ต้นไม้ครอบคลุมขั้นต่ำ เป็นหนึ่งในแนวคิดสำคัญในทฤษฎีกราฟ โดยเฉพาะในกราฟที่มีน้ำหนัก (weighted graph) ที่ไม่มีทิศทาง (undirected graph) MST เป็นต้นไม้ (tree) ที่ครอบคลุมทุกจุด (vertices) ในกราฟ และมีผลรวมน้ำหนักของเส้นเชื่อม (edges) ต่ำที่สุดเมื่อเทียบกับต้นไม้ครอบคลุมอื่น ๆ ที่เป็นไปได้ในกราฟนั้น

จุดประสงค์ของการหา Minimum Spanning Tree

  1. ลดค่าใช้จ่าย: ใช้ในการหาวิธีการเชื่อมต่อทุกจุดในกราฟโดยใช้น้ำหนักรวมของเส้นเชื่อมที่น้อยที่สุด ซึ่งสามารถประยุกต์ใช้ได้ในหลายกรณี เช่น การออกแบบเครือข่ายคอมพิวเตอร์, การวางระบบท่อ, การวางสายไฟฟ้า หรือการออกแบบโครงสร้างพื้นฐานอื่น ๆ ที่ต้องการลดต้นทุนในการเชื่อมต่อ
  2. ประสิทธิภาพในเครือข่าย: ใช้ในการเพิ่มประสิทธิภาพและลดการซ้ำซ้อนในเครือข่าย เช่น ในการสร้างเครือข่ายการสื่อสารที่มีประสิทธิภาพและมีค่าใช้จ่ายต่ำ
  3. การวิเคราะห์และเพิ่มประสิทธิภาพระบบ: ใช้ในการวิเคราะห์ระบบที่มีอยู่และปรับปรุงประสิทธิภาพ เช่น การหาเส้นทางการขนส่งที่ประหยัดที่สุด หรือการออกแบบเส้นทางการเดินทางที่มีค่าใช้จ่ายต่ำ

ตัวอย่างการประยุกต์ใช้ Minimum Spanning Tree

  1. การออกแบบเครือข่ายคอมพิวเตอร์ หา MST เพื่อออกแบบเครือข่ายที่เชื่อมโยงเครื่องคอมพิวเตอร์ทั้งหมดด้วยค่าใช้จ่ายต่ำที่สุด
  2. **การวางระบบท่อหรือสายไฟ **ใช้ MST ในการวางระบบท่อหรือสายไฟเพื่อเชื่อมต่อทุกบ้านในเมืองด้วยค่าใช้จ่ายน้อยที่สุด
  3. **การวางแผนเส้นทางการขนส่ง **ใช้ MST ในการวางแผนเส้นทางการขนส่งเพื่อหาวิธีที่ประหยัดต้นทุนและมีประสิทธิภาพในการขนส่งสินค้าระหว่างจุดต่าง ๆ

อัลกอริทึมในการหา Minimum Spanning Tree

มีอัลกอริทึมหลัก ๆ ที่ใช้ในการหา MST ดังนี้:

  1. Kruskal's Algorithm
  • เริ่มต้นด้วยการเรียงลำดับเส้นเชื่อมทั้งหมดตามน้ำหนักจากน้อยไปมาก
  • เพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดเข้าไปในต้นไม้ครอบคลุมโดยไม่ทำให้เกิดวงจร (cycle)
  • ทำซ้ำจนกว่าจะได้เส้นเชื่อมจำนวน 𝑉−1V−1 เส้น (โดยที่ 𝑉V คือจำนวนจุด)

2. Prim's Algorithm

  • เริ่มต้นจากจุดหนึ่งในกราฟ

  • เพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดที่เชื่อมกับจุดที่ยังไม่ได้อยู่ในต้นไม้ครอบคลุม

  • ทำซ้ำจนกว่าจะครอบคลุมทุกจุดในกราฟ

Prim's Algorithm

Prim's Algorithm เป็นหนึ่งในอัลกอริทึมที่ใช้ในการหา Minimum Spanning Tree (MST) ของกราฟที่มีน้ำหนัก (weighted graph) และไม่มีทิศทาง (undirected graph) โดยเริ่มจากจุดหนึ่งและขยายต้นไม้ครอบคลุม (spanning tree) ทีละจุดโดยเลือกเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดที่เชื่อมกับจุดที่ยังไม่ได้อยู่ในต้นไม้ครอบคลุม
หลักการทำงานของ Prim's Algorithm

  1. เลือกจุดเริ่มต้น: เลือกจุดเริ่มต้นใด ๆ ในกราฟและทำเครื่องหมายว่าอยู่ในต้นไม้ครอบคลุมแล้ว
  2. ค้นหาเส้นเชื่อมที่มีน้ำหนักน้อยที่สุด: ค้นหาเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดที่เชื่อมจากจุดในต้นไม้ครอบคลุมไปยังจุดที่ยังไม่อยู่ในต้นไม้ครอบคลุม
  3. เพิ่มเส้นเชื่อมในต้นไม้ครอบคลุม: เพิ่มเส้นเชื่อมที่เลือกและทำเครื่องหมายจุดปลายทางว่าอยู่ในต้นไม้ครอบคลุมแล้ว
  4. ทำซ้ำ: ทำซ้ำขั้นตอนที่ 2 และ 3 จนกว่าจุดทั้งหมดจะถูกรวมอยู่ในต้นไม้ครอบคลุม
#include <climits>
#include <iostream>
#include <vector>

using namespace std;

// Function to find the vertex with minimum key value
int minKey(vector<int> &key, vector<bool> &mstSet, int V) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (!mstSet[v] && key[v] < min)
min = key[v], min_index = v;
return min_index;
}

// Function to print the constructed MST stored in parent[]
void printMST(vector<int> &parent, vector<vector<int>> &graph, int V) {
cout << "Edge \tWeight\n";
for (int i = 1; i < V; i++)
cout << parent[i] << " - " << i << "\t" << graph[i][parent[i]] << " \n";
}

// Function to construct and print MST for a graph represented using adjacency
// matrix
void primMST(vector<vector<int>> &graph, int V) {
vector<int> parent(V); // Array to store constructed MST
vector<int> key(
V, INT_MAX); // Key values used to pick minimum weight edge in cut
vector<bool> mstSet(V, false); // To represent set of vertices included in MST

// Initialize the first vertex's key as 0 so that it is picked as first vertex
key[0] = 0;
parent[0] = -1; // First node is always root of MST

// The MST will have V vertices
for (int count = 0; count < V - 1; count++) {
// Pick the minimum key vertex from the set of vertices not yet included in
// MST
int u = minKey(key, mstSet, V);

// Add the picked vertex to the MST set
mstSet[u] = true;

// Update key value and parent index of the adjacent vertices of the picked
// vertex
for (int v = 0; v < V; v++) {
// graph[u][v] is non-zero only for adjacent vertices
// mstSet[v] is false for vertices not yet included in MST
// Update the key only if graph[u][v] is smaller than key[v]
if (graph[u][v] && !mstSet[v] && graph[u][v] < key[v])
parent[v] = u, key[v] = graph[u][v];
}
}

// Print the constructed MST
printMST(parent, graph, V);
}

int main() {
// Define the number of vertices in the graph
int V = 5;

// Define the graph as an adjacency matrix
vector<vector<int>> graph = {
{0, 2, 0, 6, 0}, {2, 0, 3, 8, 5}, {0, 3, 0, 0, 7},
{6, 8, 0, 0, 9}, {0, 5, 7, 9, 0},
};

// Run Prim's Algorithm
primMST(graph, V);

return 0;
}

อธิบายโค้ด

  1. การตั้งค่าและประกาศตัวแปร:
    • minKey เป็นฟังก์ชันที่หา vertex ที่มีค่า key น้อยที่สุดจากกลุ่มที่ยังไม่รวมใน MST
    • printMST เป็นฟังก์ชันที่พิมพ์ผลลัพธ์ของ MST ที่สร้างขึ้น
    • primMST เป็นฟังก์ชันหลักที่ใช้ Prim's Algorithm ในการหาต้นไม้ครอบคลุมขั้นต่ำ
  2. ฟังก์ชัน primMST:
    • ใช้ vector<int> parent เพื่อเก็บค่า parent ของแต่ละ vertex ใน MST
    • ใช้ vector<int> key เพื่อเก็บค่า key ที่ใช้ในการเลือกเส้นเชื่อมที่มีน้ำหนักน้อยที่สุด
    • ใช้ vector<bool> mstSet เพื่อเก็บสถานะของแต่ละ vertex ว่าถูกรวมใน MST หรือไม่
  3. การวนลูปเพื่อสร้าง MST:
    • เลือก vertex ที่มีค่า key น้อยที่สุดที่ยังไม่รวมใน MST
    • ทำเครื่องหมาย vertex นั้นว่าอยู่ใน MST แล้ว
    • อัปเดตค่า key และ parent ของ vertex ที่เชื่อมกับ vertex ที่เลือก โดยเลือกเส้นเชื่อมที่มีน้ำหนักน้อยที่สุด
  4. การเรียกใช้งาน:
    • กำหนดจำนวน vertex และกราฟในรูปแบบของ adjacency matrix
    • เรียกใช้ฟังก์ชัน primMST เพื่อหาต้นไม้ครอบคลุมขั้นต่ำและพิมพ์ผลลัพธ์

โดยนี่คือ ภาพ กราฟต้นฉบับ
original-prim.webp
และนี่คือ MST ที่ได้จาก Prim
result-prim.webp
Code Complexity ของ Prim's Algorithm
วิเคราะห์ Time Complexity จาก

  1. Initialization:
    • การตั้งค่าค่าเริ่มต้นสำหรับ key และ mstSet ใช้เวลา 𝑂(𝑉)O(V) ซึ่ง 𝑉V คือจำนวนจุด (vertices) ในกราฟ
    • การตั้งค่า key[0] = 0 และ parent[0] = -1 ใช้เวลา 𝑂(1)O(1)
  2. Finding the Minimum Key Vertex:
    • การค้นหา vertex ที่มีค่า key น้อยที่สุดในฟังก์ชัน minKey ใช้เวลา 𝑂(𝑉)O(V) ในการวนลูปค้นหาในทุกครั้งของการวนลูปหลัก
    • เนื่องจากการค้นหานี้จะถูกเรียกใช้ 𝑉−1V−1 ครั้งในลูปหลัก ดังนั้นเวลาที่ใช้รวมคือ 𝑂(𝑉2)O(V2)
  3. Updating Key and Parent Arrays:
    • สำหรับ vertex แต่ละตัวที่ถูกเลือกในลูปหลัก จะมีการอัปเดตค่า key และ parent ของ vertices ที่เชื่อมต่อกับ vertex ที่เลือก
    • การอัปเดตนี้ใช้เวลา 𝑂(𝑉)O(V) สำหรับแต่ละ vertex
    • เวลาที่ใช้รวมคือ 𝑂(𝑉2)O(V2) เนื่องจากมี 𝑉−1V−1 ครั้งในลูปหลัก

สรุป

สำหรับ Prim's Algorithm ที่ไม่ใช้โครงสร้างข้อมูลขั้นสูงในการปรับปรุงประสิทธิภาพ:

  • Time Complexity: 𝑂(𝑉2)O(V2)
    • การค้นหา vertex ที่มีค่า key น้อยที่สุดใช้เวลา 𝑂(𝑉)O(V) ในทุกครั้งของการวนลูปหลัก
    • การอัปเดตค่า key และ parent ใช้เวลา 𝑂(𝑉)O(V) สำหรับแต่ละ vertex ที่ถูกเลือกในลูปหลัก

Space Complexity

  • Space Complexity: 𝑂(𝑉)O(V)
    • การใช้พื้นที่สำหรับเก็บค่า key และ mstSet ซึ่งมีขนาด 𝑂(𝑉)O(V)
    • การใช้พื้นที่สำหรับเก็บค่า parent ซึ่งมีขนาด 𝑂(𝑉)O(V)
    • การเก็บข้อมูลกราฟในรูปแบบ adjacency matrix ใช้พื้นที่ 𝑂(𝑉2)O(V2) ซึ่งเป็นพื้นที่หลักที่ใช้

ปรับปรุง Prim's Algorithm ด้วย Priority Queue

ในการปรับปรุงประสิทธิภาพของ Prim's Algorithm สามารถใช้ Priority Queue เพื่อปรับปรุงการค้นหา vertex ที่มีค่า key น้อยที่สุด:

  • การใช้ Priority Queue (เช่น Min-Heap) จะลดเวลาในการค้นหา vertex ที่มีค่า key น้อยที่สุดจาก 𝑂(𝑉)O(V) เป็น 𝑂(log⁡𝑉)O(logV)
  • เวลาที่ใช้ในการอัปเดตค่า key ใน Priority Queue จะเป็น 𝑂(log⁡𝑉)O(logV) ต่อการอัปเดตหนึ่งครั้ง

ดังนั้น Time Complexity ของ Prim's Algorithm ที่ใช้ Priority Queue จะเป็น:

  • Time Complexity: 𝑂(𝐸log⁡𝑉)O(ElogV)
    • การเพิ่ม vertex ลงใน Priority Queue ใช้เวลา 𝑂(log⁡𝑉)O(logV)
    • การอัปเดตค่า key ใน Priority Queue ใช้เวลา 𝑂(log⁡𝑉)O(logV)
    • มีการอัปเดตทั้งหมด 𝐸E ครั้ง (จำนวนเส้นเชื่อม)

การใช้ Priority Queue จะทำให้ Prim's Algorithm มีประสิทธิภาพดีขึ้นเมื่อทำงานกับกราฟที่มีจำนวนเส้นเชื่อมมาก (dense graph)

Kruskal's Algorithm

Kruskal's Algorithm เป็นหนึ่งในอัลกอริทึมที่ใช้ในการหา Minimum Spanning Tree (MST) ของกราฟที่มีน้ำหนัก (weighted graph) และไม่มีทิศทาง (undirected graph) โดยอัลกอริทึมนี้ทำงานโดยการเรียงลำดับเส้นเชื่อมทั้งหมดตามน้ำหนักจากน้อยไปมาก จากนั้นเลือกเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดทีละเส้นเพื่อเพิ่มเข้าไปในต้นไม้ครอบคลุม (spanning tree) โดยต้องมั่นใจว่าเส้นเชื่อมนั้นไม่ทำให้เกิดวงจร (cycle)

หลักการทำงานของ Kruskal's Algorithm

  1. การเรียงลำดับเส้นเชื่อม:
    • เรียงลำดับเส้นเชื่อมทั้งหมดในกราฟตามน้ำหนักจากน้อยไปมาก
  2. การใช้โครงสร้างข้อมูล Union-Find:
    • ใช้โครงสร้างข้อมูล Union-Find เพื่อเก็บและตรวจสอบส่วนที่เชื่อมต่อกันของกราฟ เพื่อให้แน่ใจว่าเส้นเชื่อมที่เลือกจะไม่ทำให้เกิดวงจร
  3. การเลือกเส้นเชื่อม:
    • เริ่มจากเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดและเพิ่มเข้าไปในต้นไม้ครอบคลุม
    • ทำการรวมส่วนที่เชื่อมต่อกันใน Union-Find
    • ทำซ้ำจนกว่าจะมีเส้นเชื่อมจำนวน 𝑉−1V−1 เส้นในต้นไม้ครอบคลุม (โดยที่ 𝑉V คือจำนวนจุด)
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

// โครงสร้างที่ใช้แทนขอบ (edge) ของกราฟ
struct Edge {
int src, dest, weight;
};

// โครงสร้างที่ใช้แทนกราฟ
struct Graph {
int V, E;
vector<Edge> edges;
};

// โครงสร้างที่ใช้สำหรับ Union-Find
struct Subset {
int parent;
int rank;
};

// ฟังก์ชันเปรียบเทียบน้ำหนักของขอบ
bool compareEdges(Edge a, Edge b) { return a.weight < b.weight; }

// ฟังก์ชันหา root ของชุดที่ประกอบด้วย element i
int find(vector<Subset> &subsets, int i) {
if (subsets[i].parent != i) {
subsets[i].parent = find(subsets, subsets[i].parent);
}
return subsets[i].parent;
}

// ฟังก์ชันรวมชุดสองชุดเข้าด้วยกัน
void unionSubsets(vector<Subset> &subsets, int x, int y) {
int xroot = find(subsets, x);
int yroot = find(subsets, y);

if (subsets[xroot].rank < subsets[yroot].rank) {
subsets[xroot].parent = yroot;
} else if (subsets[xroot].rank > subsets[yroot].rank) {
subsets[yroot].parent = xroot;
} else {
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}

// ฟังก์ชันหลักที่ใช้ Kruskal's Algorithm ในการหา MST
void kruskalMST(Graph &graph) {
vector<Edge> result;
int V = graph.V;
vector<Subset> subsets(V);

for (int v = 0; v < V; ++v) {
subsets[v].parent = v;
subsets[v].rank = 0;
}

sort(graph.edges.begin(), graph.edges.end(), compareEdges);

for (Edge &edge : graph.edges) {
int x = find(subsets, edge.src);
int y = find(subsets, edge.dest);

if (x != y) {
result.push_back(edge);
unionSubsets(subsets, x, y);
}
}

cout << "Following are the edges in the constructed MST\n";
for (Edge &edge : result) {
cout << edge.src << " -- " << edge.dest << " == " << edge.weight << endl;
}
}

int main() {
int V = 4; // Number of vertices in graph
int E = 5; // Number of edges in graph

Graph graph;
graph.V = V;
graph.E = E;

// Adding edges
graph.edges.push_back({0, 1, 10});
graph.edges.push_back({0, 2, 6});
graph.edges.push_back({0, 3, 5});
graph.edges.push_back({1, 3, 15});
graph.edges.push_back({2, 3, 4});

kruskalMST(graph);

return 0;
}

อธิบายโค้ด

  1. การกำหนดโครงสร้างข้อมูล:
    • โครงสร้าง Edge ใช้แทนเส้นเชื่อม (edge) ของกราฟ โดยเก็บข้อมูลจุดเริ่มต้น ( src), จุดปลายทาง ( dest) และน้ำหนัก ( weight)
    • โครงสร้าง Graph ใช้แทนกราฟ โดยเก็บจำนวนจุด ( V) และจำนวนเส้นเชื่อม ( E) และรายชื่อของเส้นเชื่อม
    • โครงสร้าง Subset ใช้สำหรับ Union-Find โดยเก็บพ่อ ( parent) และระดับ ( rank) ของแต่ละชุด
  2. ฟังก์ชันสำหรับการจัดการ Union-Find:
    • find ใช้หา root ของชุดที่ประกอบด้วย element i
    • unionSubsets ใช้รวมชุดสองชุดเข้าด้วยกัน โดยใช้การจัดการระดับ ( rank) เพื่อให้การรวมมีประสิทธิภาพมากขึ้น
  3. ฟังก์ชันหลัก kruskalMST:
    • เริ่มต้นโดยการจัดเรียงเส้นเชื่อมตามน้ำหนักจากน้อยไปมาก
    • ใช้ Union-Find ในการตรวจสอบว่าการเพิ่มเส้นเชื่อมจะไม่ทำให้เกิดวงจร
    • เพิ่มเส้นเชื่อมที่ไม่ทำให้เกิดวงจรเข้าไปในผลลัพธ์ (MST)
    • พิมพ์ผลลัพธ์ของเส้นเชื่อมที่เป็นส่วนหนึ่งของ MST

โดยนี่คือ ภาพ กราฟต้นฉบับ
original_uml_kruskal.webp
และนี่คือ MST ที่ได้จาก Kruskal
mst_kruskal.webp
Time Complexity

  1. การเรียงลำดับเส้นเชื่อม:
    • Kruskal's Algorithm เริ่มต้นด้วยการเรียงลำดับเส้นเชื่อมทั้งหมดตามน้ำหนักจากน้อยไปมาก ซึ่งใช้เวลา 𝑂(𝐸log⁡𝐸)O(ElogE) เนื่องจากมีการเรียงลำดับ 𝐸E เส้นเชื่อม
  2. การดำเนินการ Union-Find:
    • การค้นหา (find) root ของชุดและการรวม (union) ชุดสองชุดใช้เวลา 𝑂(log⁡𝑉)O(logV) ต่อการดำเนินการหนึ่งครั้งเมื่อใช้ Union-Find พร้อมกับการบีบอัดเส้นทาง (path compression) และการจัดอันดับ (union by rank)
    • Union-Find ใช้ในการตรวจสอบว่าการเพิ่มเส้นเชื่อมจะทำให้เกิดวงจรหรือไม่ และในการรวมชุด
  3. การประมวลผลเส้นเชื่อม:
    • การวนลูปผ่านเส้นเชื่อมทั้งหมดและดำเนินการ Union-Find จะใช้เวลา 𝑂(𝐸log⁡𝑉)O(ElogV) เนื่องจากทุกเส้นเชื่อมอาจต้องใช้เวลา 𝑂(log⁡𝑉)O(logV) ในการดำเนินการ find และ union

สรุป

  • Time Complexity: 𝑂(𝐸log⁡𝐸+𝐸log⁡𝑉)O(ElogE+ElogV)
    • เนื่องจาก 𝐸log⁡𝐸ElogE สามารถเขียนเป็น 𝑂(𝐸log⁡𝑉)O(ElogV) ในกรณีทั่วไปที่ 𝐸≤𝑉2E≤V2
    • ดังนั้น Time Complexity โดยรวมจะเป็น 𝑂(𝐸log⁡𝑉)O(ElogV)

Space Complexity

  • Space Complexity: 𝑂(𝑉+𝐸)O(V+E)
    • การเก็บข้อมูลของกราฟในรูปแบบของโครงสร้าง edges ใช้พื้นที่ 𝑂(𝐸)O(E)
    • การเก็บข้อมูลสำหรับ Union-Find ใช้พื้นที่ 𝑂(𝑉)O(V)

การวิเคราะห์รายละเอียด

  1. Initialization:
    • การกำหนดค่าพื้นฐานในโครงสร้าง Union-Find ใช้เวลา 𝑂(𝑉)O(V)
  2. Edge Sorting:
    • การเรียงลำดับเส้นเชื่อมทั้งหมดใช้เวลา 𝑂(𝐸log⁡𝐸)O(ElogE)
  3. Processing Edges:
    • การประมวลผลเส้นเชื่อมแต่ละเส้นโดยใช้ Union-Find ใช้เวลา 𝑂(𝐸log⁡𝑉)O(ElogV)
    • การดำเนินการ find และ union สำหรับแต่ละเส้นเชื่อมใช้เวลา 𝑂(log⁡𝑉)O(logV)

ความแตกต่างระหว่าง Prim และ Kruskal

Prim's Algorithm และ Kruskal's Algorithm เป็นสองอัลกอริทึมที่นิยมใช้ในการหา Minimum Spanning Tree (MST) ในกราฟที่มีน้ำหนัก แต่มีหลักการและขั้นตอนที่แตกต่างกันไป ดังนี้คือความแตกต่างหลักระหว่าง Prim's Algorithm และ Kruskal's Algorithm:

หลักการทำงาน

  1. Prim's Algorithm:
    • เริ่มต้นจากจุดใดจุดหนึ่งในกราฟและค่อย ๆ ขยายต้นไม้ครอบคลุมขั้นต่ำ (MST) โดยเพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดที่เชื่อมกับจุดที่ยังไม่ได้อยู่ใน MST
    • การขยายต้นไม้ครอบคลุมขั้นต่ำจะเกิดขึ้นภายในจุดที่เชื่อมกันอยู่แล้ว (ภายในกราฟที่มีการเชื่อมต่อ)
  2. Kruskal's Algorithm:
    • เริ่มต้นด้วยการเรียงลำดับเส้นเชื่อมทั้งหมดตามน้ำหนักจากน้อยไปมาก
    • เพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดเข้าไปใน MST โดยไม่ทำให้เกิดวงจร (cycle)
    • การเชื่อมต่อจะเกิดขึ้นระหว่างจุดที่ยังไม่ได้เชื่อมต่อกัน (สามารถเชื่อมระหว่างส่วนของกราฟที่แยกกันได้)

ขั้นตอนการทำงาน

  1. Prim's Algorithm:
    • เลือกจุดเริ่มต้น
    • ใช้โครงสร้างข้อมูลที่สามารถหาเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดได้อย่างรวดเร็ว เช่น Priority Queue
    • เพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดที่เชื่อมกับจุดที่ยังไม่ได้อยู่ใน MST
    • ทำซ้ำจนกว่าจุดทั้งหมดจะถูกรวมอยู่ใน MST
  2. Kruskal's Algorithm:
    • เรียงลำดับเส้นเชื่อมทั้งหมดตามน้ำหนัก
    • ใช้โครงสร้างข้อมูลเช่น Union-Find เพื่อจัดการกับวงจร (cycle) และส่วนที่เชื่อมต่อกันของกราฟ
    • เพิ่มเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดเข้าไปใน MST โดยไม่ทำให้เกิดวงจร
    • ทำซ้ำจนกว่าจะมีเส้นเชื่อมจำนวน 𝑉−1V−1 เส้น (โดยที่ 𝑉V คือจำนวนจุดในกราฟ)

การประยุกต์ใช้และประสิทธิภาพ

  1. Prim's Algorithm:
    • เหมาะสมกับกราฟที่มีจุดเชื่อมต่อกันอยู่แล้ว (dense graph)
    • มีความซับซ้อนเวลาในการทำงานเป็น 𝑂(𝐸+𝑉log⁡𝑉)O(E+VlogV) โดยใช้ Priority Queue (E คือจำนวนเส้นเชื่อม, V คือจำนวนจุด)
    • ประสิทธิภาพดีในกราฟที่มีการเชื่อมต่อหนาแน่น
  2. Kruskal's Algorithm:
    • เหมาะสมกับกราฟที่มีจุดเชื่อมต่อกันบางส่วน (sparse graph)
    • มีความซับซ้อนเวลาในการทำงานเป็น 𝑂(𝐸log⁡𝐸)O(ElogE) หรือ 𝑂(𝐸log⁡𝑉)O(ElogV) โดยใช้ Union-Find (เนื่องจาก 𝐸log⁡𝐸ElogE จะเท่ากับ 𝐸log⁡𝑉ElogV ในกรณีทั่วไป)
    • ประสิทธิภาพดีในกราฟที่มีการเชื่อมต่อเบาบาง

สรุป

  • Prim's Algorithm:
    • เริ่มจากจุดใดจุดหนึ่งและขยายต้นไม้ครอบคลุมภายในจุดที่เชื่อมกันอยู่แล้ว
    • ใช้โครงสร้างข้อมูลที่สามารถหาเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดได้อย่างรวดเร็ว
    • เหมาะกับกราฟที่มีการเชื่อมต่อหนาแน่น
  • Kruskal's Algorithm:
    • เริ่มจากเส้นเชื่อมที่มีน้ำหนักน้อยที่สุดและเพิ่มเส้นเชื่อมโดยไม่ทำให้เกิดวงจร
    • ใช้โครงสร้างข้อมูล Union-Find เพื่อจัดการกับการเชื่อมต่อและการตรวจสอบวงจร
    • เหมาะกับกราฟที่มีการเชื่อมต่อเบาบาง