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:
- Đầu tiên, sắp xếp các đỉnh của đồ thị G theo thứ tự giảm dần của bậc (degree).
- Khởi tạo một mảng Color để lưu trữ màu của từng đỉnh, ban đầu các đỉnh đều chưa được tô màu (Color[v] = 0).
- Dùng biến currentColor để theo dõi màu hiện tại đang sử dụng.
- Duyệt qua từng đỉnh v của G:
- Nếu đỉnh v chưa được tô màu (Color[v] = 0), tô nó bằng màu hiện tại (currentColor).
- Sau đó, duyệt qua các đỉnh kề u của v và tô chúng cùng màu nếu chưa được tô.
- Tăng currentColor lên 1 để sử dụng màu khác cho các đỉnh tiếp theo.
- Thuật toán trả về mảng Color, trong đó mỗi phần tử là màu tương ứng của từng đỉnh.
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(), [°ree](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;
}