Đường Đi - Chu Trình Euler¶
Tác giả: FPTOJ Team
Nội dung tham khảo từ: VNOI Wiki, CP-Algorithms - Eulerian Path
1. Bản chất vấn đề¶
Bài toán: Đường đi qua mọi cạnh đúng 1 lần¶
Cho đồ thị \(N\) đỉnh, \(M\) cạnh. Tìm đường đi (hoặc chu trình) đi qua mỗi cạnh đúng 1 lần.
- Đường đi Euler (Eulerian Path): Đi qua mỗi cạnh đúng 1 lần, không cần quay về điểm đầu.
- Chu trình Euler (Eulerian Circuit): Đi qua mỗi cạnh đúng 1 lần, quay về điểm đầu.
Điều kiện tồn tại¶
Đồ thị vô hướng (liên thông):
| Loại | Điều kiện |
|---|---|
| Chu trình Euler | Mọi đỉnh đều có bậc chẵn |
| Đường đi Euler | Có đúng 2 đỉnh bậc lẻ (2 đỉnh đó là đầu và cuối) |
Đồ thị có hướng (liên thông yếu):
| Loại | Điều kiện |
|---|---|
| Chu trình Euler | Mọi đỉnh: \(\text{in-degree} = \text{out-degree}\) |
| Đường đi Euler | Có đúng 1 đỉnh \(\text{out} - \text{in} = 1\) (đầu) và 1 đỉnh \(\text{in} - \text{out} = 1\) (cuối) |
2. Tư duy cốt lõi¶
Hierholzer's Algorithm¶
Ý tưởng: Bắt đầu từ đỉnh đầu, đi theo cạnh chưa thăm cho đến khi quay về (hoặc hết đường). Nếu còn cạnh chưa thăm → chèn chu trình mới vào đường đi hiện tại.
Tại sao không dùng DFS thường? DFS có thể "cắt" đồ thị thành 2 phần không liên thông.
Trace chi tiết¶
Đồ thị: 4 đỉnh, 5 cạnh (vô hướng).
| Cạnh |
|---|
| \(0 - 1\) |
| \(1 - 2\) |
| \(2 - 0\) |
| \(0 - 3\) |
| \(3 - 2\) |
Bậc: \(\text{deg}(0) = 3\), \(\text{deg}(1) = 2\), \(\text{deg}(2) = 3\), \(\text{deg}(3) = 2\)
Hai đỉnh bậc lẻ: 0 và 2 \(\Rightarrow\) Đường đi Euler từ 0 đến 2 (hoặc ngược lại).

Chạy Hierholzer từ đỉnh 0:
| Bước | Đỉnh hiện tại | Cạnh chọn | Stack (đường đi) |
|---|---|---|---|
| 1 | 0 | 0→1 | \([0, 1]\) |
| 2 | 1 | 1→2 | \([0, 1, 2]\) |
| 3 | 2 | 2→0 | \([0, 1, 2, 0]\) |
| 4 | 0 | 0→3 | \([0, 1, 2, 0, 3]\) |
| 5 | 3 | 3→2 | \([0, 1, 2, 0, 3, 2]\) |
Kết quả: \(0 \to 1 \to 2 \to 0 \to 3 \to 2\) — đi qua mỗi cạnh đúng 1 lần!
Minh họa thuật toán¶
3. Phân tích tính đúng đắn¶
Tại sao Hierholzer hoạt động?¶
Bất biến: Mọi đỉnh trong đồ thị Euler đều có bậc chẵn (hoặc chênh lệch đúng 1 cho đường đi). Khi đi qua 1 cạnh, bậc giảm đi 1. Do đó, khi "mắc kẹt" tại đỉnh \(v\), bậc của \(v\) = 0 (đã đi hết cạnh). Mọi đỉnh trung gian đều có bậc chẵn → khi đi vào thì phải đi ra được.
Điều này đảm bảo: khi "mắc kẹt", ta đã tạo 1 chu trình con. Nếu còn cạnh chưa thăm, chu trình con đó có thể chèn vào đường đi chính.
4. Đánh giá độ phức tạp¶
| Thuật toán | Thời gian | Không gian |
|---|---|---|
| Hierholzer | \(O(N + M)\) | \(O(N + M)\) |
| Fleury | \(O(N \cdot M)\) | \(O(N + M)\) |
Hierholzer tối ưu hơn Fleury vì không cần kiểm tra cầu.