Toán tin vuotlen.com

Thuật toán Kruskal

Phân loại Thông tin
Tên thuật toán Kruskal
Phân loại thuật toán Thuật toán tham lam, thuật toán tìm cây khung nhỏ nhất (Minimum Spanning Tree)
Cấu trúc dữ liệu Ma trận kề hoặc danh sách kề
Độ phức tạp thời gian O(E log E) hoặc O(E log V) với sử dụng hàng đợi ưu tiên (Priority Queue)
Độ phức tạp dung lượng O(V²) với ma trận kề, O(E) với danh sách kề
Độ phức tạp bộ nhớ O(V²) với ma trận kề, O(E) với danh sách kề
Phạm vi sử dụng Tìm cây khung nhỏ nhất trong đồ thị vô hướng, có hoặc không có trọng số, có hoặc không liên thông
Khả năng xử lý trọng số âm Không
Khả năng xử lý chu trình âm Không
Người phát hiện đầu tiên Joseph Kruskal (1956)
Ứng dụng ban đầu Tối ưu hóa mạng điện, mạng nước, mạng giao thông
Ứng dụng hiện đại Phân cụm dữ liệu, tối ưu hóa mạng máy tính, tối ưu hóa mạng xã hội

 

Phân loại Thông tin
Ưu điểm - Tìm cây khung nhỏ nhất hiệu quả trong đồ thị với nhiều cạnh khác nhau.
  - Đơn giản và dễ triển khai.
  - Linh hoạt với đồ thị có hoặc không có trọng số, có hoặc không liên thông.
  - Hiệu quả với đồ thị thưa.
Nhược điểm - Không thể xử lý đồ thị có trọng số âm.
  - Có thể không tìm ra cây khung nhỏ nhất duy nhất trong trường hợp có nhiều cây khung nhỏ nhất cùng giá trị.
  - Độ phức tạp thời gian có thể cao nếu sử dụng ma trận kề với đồ thị dày đặc.

Chi Tiết Kỹ Thuật:

Pseudocode cho Kruskal:

Kruskal(Graph G):
    edges = sorted_edges(G)  # Sắp xếp các cạnh của đồ thị theo trọng số tăng dần
    forest = DisjointSet()   # Khởi tạo một tập hợp con rời rạc (disjoint set)
    MST = []                  # Khởi tạo một danh sách rỗng để lưu trữ cây khung nhỏ nhất

    for each vertex v in G:
        forest.make_set(v)    # Tạo một tập hợp con cho mỗi đỉnh

    for each edge (u, v, w) in edges:
        if forest.find_set(u) ≠ forest.find_set(v):  # Kiểm tra xem hai đỉnh của cạnh này có thuộc về cùng một tập hợp con hay không
            MST.append((u, v, w))                   # Thêm cạnh vào cây khung nhỏ nhất
            forest.union(u, v)                      # Hợp nhất hai tập hợp con lại

    return MST  # Trả về cây khung nhỏ nhất

code C++:

//https://nguyenvanhieu.vn/thuat-toan-prim/
#include <bits/stdc++.h>

using namespace std;

const int V = 6;  // Số lượng đỉnh trong đồ thị

struct Edge {
    int src, dest, weight;  // Cấu trúc lưu trữ thông tin của cạnh (đỉnh nguồn, đỉnh đích, trọng số)
};

// Hàm tìm đại diện (root) của tập hợp chứa phần tử i
int findSet(int i, vector<int>& parent) {
    if (parent[i] == i)
        return i;
    return findSet(parent[i], parent);
}

// Hàm hợp nhất hai tập hợp chứa u và v
void unionSets(int u, int v, vector<int>& parent, vector<int>& rank) {
    int rootU = findSet(u, parent);
    int rootV = findSet(v, parent);
    
    // Nếu hai đỉnh thuộc hai tập hợp khác nhau, hợp nhất chúng lại
    if (rootU != rootV) {
        if (rank[rootU] < rank[rootV]) {
            parent[rootU] = rootV;
        } else if (rank[rootU] > rank[rootV]) {
            parent[rootV] = rootU;
        } else {
            parent[rootV] = rootU;
            rank[rootU]++;
        }
    }
}

// Hàm tìm cây khung tối thiểu sử dụng thuật toán Kruskal
vector<Edge> kruskalMST(vector<Edge>& edges) {
    vector<int> parent(V);  // Mảng đại diện cho cha của mỗi đỉnh
    vector<int> rank(V, 0);  // Mảng lưu độ sâu của cây
    vector<Edge> mst;  // Danh sách các cạnh trong cây khung tối thiểu

    // Khởi tạo cấu trúc Union-Find
    for (int i = 0; i < V; ++i)
        parent[i] = i;

    // Sắp xếp các cạnh theo thứ tự tăng dần của trọng số
    sort(edges.begin(), edges.end(), [](Edge a, Edge b) {
        return a.weight < b.weight;
    });

    // Duyệt qua các cạnh và thêm vào cây khung tối thiểu nếu không tạo thành chu trình
    for (Edge& edge : edges) {
        if (findSet(edge.src, parent) != findSet(edge.dest, parent)) {
            mst.push_back(edge);
            unionSets(edge.src, edge.dest, parent, rank);
        }
    }

    return mst;
}

int main() {
    int graph[V][V] = {
        {0, 6, 1, 5, 0, 0},
        {6, 0, 5, 0, 3, 0},
        {1, 5, 0, 5, 6, 4},
        {5, 0, 5, 0, 0, 2},
        {0, 3, 6, 0, 0, 6},
        {0, 0, 4, 2, 6, 0}
    };

    vector<Edge> edges;

    // Chuyển đổi ma trận trọng số thành danh sách các cạnh
    for (int i = 0; i < V; ++i) {
        for (int j = i + 1; j < V; ++j) {
            if (graph[i][j] != 0) {
                edges.push_back({i, j, graph[i][j]});
            }
        }
    }

    // Tìm cây khung tối thiểu sử dụng Kruskal
    vector<Edge> mst = kruskalMST(edges);
    int totalWeight = 0;

    // In ra các cạnh của cây khung tối thiểu và tổng trọng số
    for (Edge& edge : mst) {
        cout << "Canh: " << edge.src << " - " << edge.dest << " voi trong so " << edge.weight << endl;
        totalWeight += edge.weight;
    }

    cout << "Tong trong so cua cay khung toi thieu: " << totalWeight << endl;

    return 0;
}