Toán tin vuotlen.com

Bài toán tô màu

Phân loại Thông tin
Tên thuật toán Thuật toán tô màu đồ thị
Phân loại thuật toán Thuật toán Welsh-Powell
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(V²) với ma trận kề, O(V + E) với danh sách kề
Độ phức tạp dung lượng O(V²) với ma trận kề, O(V + E) với danh sách kề
Độ phức tạp bộ nhớ O(V²) với ma trận kề, O(V + E) với danh sách kề
Phạm vi sử dụng Tìm số màu tối thiểu cần thiết để tô màu các đỉnh của đồ thị sao cho không có hai đỉnh kề nhau có cùng màu
Khả năng xử lý trọng số âm Không áp dụng (thuật toán tô màu không liên quan đến trọng số cạnh)
Khả năng xử lý chu trình âm Không áp dụng (thuật toán tô màu không liên quan đến chu trình âm)
Người phát hiện đầu tiên Heinrich Heesch và Kenneth Appel cùng Wolfgang Haken (định lý bốn màu)
Ứng dụng ban đầu Tô màu bản đồ, đảm bảo rằng không có hai vùng kề nhau có cùng màu
Ứng dụng hiện đại Lập lịch, phân công công việc, tô màu bản đồ, tối ưu hóa mạng, phân bổ tài nguyên, kiểm thử phần mềm

 

Ưu điểm Nhược điểm
Giải quyết hiệu quả các bài toán phân công tài nguyên và lập lịch. Không đảm bảo kết quả tối ưu nhất với mọi trường hợp.
Đơn giản và dễ triển khai. Đối với đồ thị phức tạp, có thể yêu cầu số lượng màu lớn hơn số lượng cần thiết (không tối ưu).
Có thể sử dụng các phương pháp tham lam đơn giản như Welsh-Powell, có hiệu quả với nhiều loại đồ thị. Khó khăn trong việc tìm số màu tối thiểu cho đồ thị lớn và phức tạp.
Áp dụng được trong nhiều lĩnh vực thực tế như mạng máy tính, tối ưu hóa, định tuyến. Với đồ thị ngẫu nhiên, có thể phải thử nhiều cách sắp xếp khác nhau để tìm ra giải pháp tốt nhất.
Hữu ích trong việc kiểm thử phần mềm và đảm bảo không có xung đột tài nguyên. Đối với đồ thị đặc biệt phức tạp, có thể cần sử dụng các thuật toán phức tạp hơn như thuật toán quay lui.

 

Kỹ thuật Mô tả
Phương pháp tham lam Chọn một đỉnh và gán màu đầu tiên có thể (màu không trùng với màu của các đỉnh kề), sau đó tiếp tục với các đỉnh còn lại.
Thuật toán Welsh-Powell Sắp xếp các đỉnh theo thứ tự bậc giảm dần, sau đó tô màu các đỉnh theo thứ tự đã sắp xếp, chọn màu đầu tiên có thể cho mỗi đỉnh.
Thuật toán Backtracking Thử các màu cho các đỉnh theo thứ tự, nếu gặp xung đột thì quay lui để thử màu khác, cho đến khi tìm được giải pháp hợp lệ.
Thuật toán DSATUR Chọn đỉnh có số đỉnh kề được tô màu nhiều nhất để tô màu tiếp theo, đảm bảo số màu sử dụng ít nhất.
Thuật toán Largest First Sắp xếp các đỉnh theo số lượng đỉnh kề (degree) giảm dần, sau đó tô màu các đỉnh theo thứ tự đã sắp xếp, chọn màu đầu tiên có thể.
Thuật toán Smallest Last Sắp xếp các đỉnh theo số lượng đỉnh kề (degree) tăng dần, sau đó tô màu các đỉnh theo thứ tự đã sắp xếp, chọn màu đầu tiên có thể.
Genetic Algorithm Sử dụng các khái niệm của thuật toán di truyền (genetic algorithms) để tìm kiếm một cách tối ưu số màu cần thiết.
Simulated Annealing Sử dụng kỹ thuật làm lạnh mô phỏng để tìm kiếm cách tô màu với số lượng màu ít nhất có thể bằng cách tối ưu hóa cục bộ.
Tabu Search Sử dụng một danh sách cấm (tabu list) để lưu trữ các nước đi đã thử và tránh lặp lại, giúp tìm kiếm một cách tô màu tối ưu hơn.
Recursive Largest First Chọn đỉnh có bậc lớn nhất, tô màu đỉnh đó và đệ quy với phần còn lại của đồ thị sau khi đã loại bỏ đỉnh đã tô màu và các cạnh kề.

Psudo code Welsh-Powell:

procedure Welsh-Powell(Graph G)
    Sort vertices of G in decreasing order by degree
    Initialize an array Color[1..|V|] with 0 (indicating no color assigned)
    Let currentColor = 1

    for each vertex v in G
        if Color[v] = 0 then
            Color[v] = currentColor
            for each uncolored vertex u adjacent to v
                if Color[u] = 0 then
                    Color[u] = currentColor
            currentColor = currentColor + 1

    return Color

Giải thích:

code C++:

#include <bits/stdc++.h>
using namespace std;

// Hàm để sắp xếp các đỉnh theo bậc giảm dần
vector<int> sortVerticesByDegree(const vector<vector<int>>& graph) {
    int V = graph.size();
    vector<int> degree(V);

    // Tính bậc của từng đỉnh
    for (int i = 0; i < V; ++i) {
        for (int j = 0; j < V; ++j) {
            if (graph[i][j]) ++degree[i];
        }
    }

    // Sắp xếp các đỉnh theo bậc giảm dần
    vector<int> sortedVertices(V);
    for (int i = 0; i < V; ++i) {
        sortedVertices[i] = i; // Khởi tạo các đỉnh theo thứ tự ban đầu
    }
    sort(sortedVertices.begin(), sortedVertices.end(), [&degree](int a, int b) {
        return degree[a] > degree[b];
    });

    return sortedVertices;
}

// Hàm thực hiện thuật toán Welsh-Powell
void welshPowellColoring(const vector<vector<int>>& graph) {
    int V = graph.size();
    int result[100]; // Mảng lưu màu của các đỉnh, giả sử số đỉnh tối đa là 100
    fill(result, result + V, -1); // Khởi tạo mảng result với -1 (chưa tô màu)

    // Sắp xếp các đỉnh theo bậc giảm dần
    vector<int> sortedVertices = sortVerticesByDegree(graph);

    // Mảng để đánh dấu các màu đã sử dụng
    bool usedColors[100] = {false}; // Giả sử số màu tối đa là 100

    // Gán màu cho các đỉnh theo thứ tự đã sắp xếp
    for (int u : sortedVertices) {
        // Đánh dấu các màu đã sử dụng bởi các đỉnh kề
        for (int v = 0; v < V; ++v) {
            if (graph[u][v] && result[v] != -1) {
                usedColors[result[v]] = true;
            }
        }

        // Tìm màu đầu tiên có thể sử dụng
        int color;
        for (color = 0; color < V; ++color) {
            if (!usedColors[color]) {
                break;
            }
        }

        // Gán màu cho đỉnh u
        result[u] = color;

        // Đặt lại đánh dấu màu đã sử dụng
        fill(usedColors, usedColors + V, false);
    }

    // In kết quả
    for (int i = 0; i < V; ++i) {
        cout << "Dinh " << i << " -> Mau " << result[i] << endl;
    }
}

int main() {
    // Ma trận kề của đồ thị
    vector<vector<int>> graph = {
        {0, 1, 1, 0, 0, 0},
        {1, 0, 1, 1, 0, 0},
        {1, 1, 0, 1, 1, 0},
        {0, 1, 1, 0, 1, 1},
        {0, 0, 1, 1, 0, 1},
        {0, 0, 0, 1, 1, 0}
    };

    welshPowellColoring(graph);

    return 0;
}