Đườ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 đề¶
Câu chuyện mở đầu: vẽ một nét và xếp Domino¶
Bạn từng chơi trò vẽ một nét không nhấc bút? Hay xếp bộ Domino sao cho số khớp nhau nối tiếp nhau hết cả bộ? Cả hai đều là một bài toán: đi qua mỗi cạnh đúng một lần. Năm 1736, Euler giải bài toán 7 cây cầu Königsberg bằng đúng tư duy này — khai sinh lý thuyết đồ thị.
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¶
flowchart TD
A["Start tại đỉnh 0"] --> B["Đi 0→1→2→0 (chu trình con)"]
B --> C["Quay lại 0, còn cạnh 0→3"]
C --> D["Đi 0→3→2 (chu trình con)"]
D --> E["Ghép: 0→1→2→0→3→2"]
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.
Code minh họa¶
Đường đi Euler trên đồ thị có hướng¶
5. Lỗi thường gặp (SAI / ĐÚNG)¶
Lỗi 1: Chỉ kiểm tra bậc, quên liên thông yếu¶
SAI: mọi đỉnh bậc chẵn nhưng đồ thị rời rạc (2 cụm riêng) → kết luận có chu trình Euler.
ĐÚNG: thêm BFS/DFS bỏ qua đỉnh cô lập, kiểm tra mọi đỉnh có cạnh đều tới được nhau.
Lỗi 2: Chọn đỉnh bắt đầu sai¶
SAI: luôn start = 0 dù có 2 đỉnh bậc lẻ → đường đi bắt đầu giữa chừng, Hierholzer kẹt sớm.
ĐÚNG: đường đi Euler phải bắt đầu ở đỉnh bậc lẻ (có hướng: đỉnh out - in = 1); chỉ khi là chu trình mới lấy đỉnh bất kỳ có cạnh.
Lỗi 3: Quên reverse(path)¶
SAI: in path trực tiếp → thứ tự ngược (vì đỉnh được chốt lúc quay lui).
ĐÚNG: luôn đảo trước khi in.
Bài tập luyện tập¶
| Bài | Nền tảng | Độ khó | Chủ đề |
|---|---|---|---|
| euler-basic | FPTOJ | ⭐⭐ | Chu trình Euler vô hướng |
| euler-path | FPTOJ | ⭐⭐ | Đường đi Euler vô hướng |
| euler-directed | FPTOJ | ⭐⭐ | Chu trình Euler có hướng |
| euler-reconstruct | FPTOJ | ⭐⭐⭐ | Đường đi Euler có hướng |
| euler-domino | FPTOJ | ⭐⭐⭐ | Sắp xếp Domino qua Euler |
| euler-de-bruijn | FPTOJ | ⭐⭐⭐⭐ | Chuỗi De Bruijn |
| euler-word-chain | FPTOJ | ⭐⭐⭐⭐ | Sắp xếp chuỗi từ tiếng Anh |
| euler-postman | FPTOJ | ⭐⭐⭐⭐⭐ | Người đưa thư Trung Hoa |