Thuật toán Edmonds-Karp là một biến thể của thuật toán Ford-Fulkerson dùng để tìm luồng cực đại trong mạng lưới. Nó được áp dụng rộng rãi trong các bài toán tối ưu hóa mạng, như luồng cực đại trong đồ thị, cắt nhỏ nhất, cũng như trong các lĩnh vực vận tải và xử lý dữ liệu.
Khái niệm cơ bản
Trước khi khám phá chi tiết cách cài đặt, ta cần nắm vững một số khái niệm sau:
- Luồng cực đại: Đây là thuật ngữ chỉ lượng luồng lớn nhất mà ta có thể truyền từ điểm nguồn (source) tới điểm đích (sink) trong một mạng lưới.
- Đường tăng luồng (Augmenting Path): Đây là một đường đi từ nguồn tới đích mà ta có thể tăng luồng thông qua nó.
- Đồ thị thặng dư (Residual Graph): Đồ thị này biểu thị khả năng tăng luồng qua các cạnh sau khi đã có một luồng ban đầu đi qua.
Nguyên lý hoạt động
Thuật toán Edmonds-Karp sử dụng thuật toán duyệt theo chiều rộng (BFS) để tìm đường ngắn nhất từ nguồn tới đích trong đồ thị thặng dư. Quy trình này được lặp đi lặp lại cho đến khi không còn đường tăng luồng nào.
Cài đặt thuật toán
Dưới đây là cách cài đặt thuật toán bằng ngôn ngữ lập trình Python:
from collections import deque
# Hàm BFS tìm đường từ nguồn đến đích trong đồ thị thặng dư
def bfs(residual_graph, source, sink, parent):
visited = [False] * len(residual_graph)
queue = deque([source])
visited[source] = True
while queue:
u = queue.popleft()
for v, capacity in enumerate(residual_graph[u]):
if not visited[v] and capacity > 0: # Thăm đỉnh nếu chưa thăm và còn dung lượng
queue.append(v)
visited[v] = True
parent[v] = u
if v == sink:
return True
return False
# Hàm chính của thuật toán Edmonds-Karp
def edmonds_karp(graph, source, sink):
residual_graph = [row[:] for row in graph] # Tạo đồ thị thặng dư
parent = [-1] * len(graph) # Lưu vết đường đi
max_flow = 0
while bfs(residual_graph, source, sink, parent):
path_flow = float('Inf')
s = sink
# Tìm khả năng tăng luồng tối đa trên đường tìm được
while s != source:
path_flow = min(path_flow, residual_graph[parent[s]][s])
s = parent[s]
# Cập nhật dung lượng trên đường đi
v = sink
while v != source:
u = parent[v]
residual_graph[u][v] -= path_flow
residual_graph[v][u] += path_flow
v = parent[v]
max_flow += path_flow
return max_flow
# Ví dụ sử dụng
graph = [
[0, 16, 13, 0, 0, 0],
[0, 0, 10, 12, 0, 0],
[0, 4, 0, 0, 14, 0],
[0, 0, 9, 0, 0, 20],
[0, 0, 0, 7, 0, 4],
[0, 0, 0, 0, 0, 0]
]
source = 0
sink = 5
print("Giá trị luồng cực đại là:", edmonds_karp(graph, source, sink))
Giải thích
-
Hàm BFS:
- Khởi tạo hàng đợi và danh sách
visited
. - Duyệt qua các đỉnh, thêm các đỉnh kế tiếp có khả năng tăng luồng vào hàng đợi.
- Trả về
True
nếu có thể tìm thấy đường tăng luồng.
- Khởi tạo hàng đợi và danh sách
-
Hàm Edmonds-Karp chính:
- Tạo bản sao của đồ thị gốc để làm đồ thị thặng dư.
- Sử dụng BFS để tìm đường tăng luồng.
- Tính toán khả năng tăng luồng tối đa
path_flow
trên đường tìm được. - Cập nhật đồ thị thặng dư và tăng giá trị luồng cực đại dựa trên
path_flow
.
Kết luận
Thuật toán Edmonds-Karp là một trong các phương pháp hiệu quả để giải bài toán luồng cực đại, sử dụng BFS để đảm bảo tìm được đường ngắn nhất ở mỗi bước, từ đó tối ưu thời gian tìm kiếm đường tăng luồng với độ phức tạp thời gian là O(VE^2). Cài đặt trên không chỉ giải thích cơ bản mà còn cung cấp mã nguồn tham khảo giúp bạn có thể triển khai thuật toán trong các hệ thống thực tế.
Comments