Mũi tên chỉ về phần phải học trước
Trong mô hình của SGK, cạnh i→j nghĩa là **muốn học i thì phải học j trước**. Dữ liệu mẫu có 1→0,2→0,3→1,3→2,4→3. Có thể học 0, rồi 1 và 2, rồi 3, rồi 4; hệ thống không mâu thuẫn.
Nếu thêm 0→4, các yêu cầu tạo vòng 0→4→3→1→0: muốn học một phần lại phải hoàn thành các phần cuối cùng quay về chính nó. Hệ thống có thể hoàn thành mọi chuyên đề theo các ràng buộc này khi đồ thị có hướng **không có chu trình**, giả định không có ràng buộc nào khác.
Ba trạng thái có vai trò khác nhau
state=0 là chưa bắt đầu, 1 là đang nằm trên nhánh DFS hiện tại, 2 là đã duyệt xong. Gặp cạnh tới state=1 tạo đường quay về một đỉnh đang ở nhánh hiện tại, nên phát hiện chu trình. Gặp state=2 chưa đủ để kết luận có chu trình.
active lưu nhánh hiện tại. Hàm trả một danh sách đỉnh tạo chu trình, có lặp đỉnh đầu ở cuối để khép vòng; trả [] nếu không có. Phải xét cả các đỉnh chưa tới được từ lượt đầu.
```python
def cycle_visit(Adj, u, state, active):
state[u] = 1
active.append(u)
for v in Adj[u]:
if state[v] == 1:
return active[active.index(v):] + [v]
if state[v] == 0:
cycle = cycle_visit(Adj, v, state, active)
if cycle:
return cycle
active.pop()
state[u] = 2
return []
def directed_cycle(Adj):
state = [0]*len(Adj)
active = []
for u in range(len(Adj)):
if state[u] == 0:
cycle = cycle_visit(Adj, u, state, active)
if cycle:
return cycle
return []
```
Đọc tệp có hướng và xem vòng mâu thuẫn
demo.py đọc tien_quyet.inp với directed=True. Ban đầu kết quả là []. Sau khi thêm 0→4 vào bản dữ liệu trong bộ nhớ, kết quả là `[0,4,3,1,0]`.
Thử một đồ thị không chu trình có các cạnh 0→1,0→2,2→1. Khi xét từ 2, đỉnh 1 có thể đã state=2; đây là hai cách tới 1, chưa phải đường quay về 2. Không dùng một biến đã-thăm đơn thuần để kết luận mọi cạnh tới đỉnh cũ đều tạo chu trình.
Hàm này dành cho **có hướng**. Không áp nguyên xi lên danh sách kề vô hướng vì cạnh đi ngược về cha sẽ bị hiểu nhầm là quay về nhánh đang duyệt.
Bài luyện
Theo quy ước bài, cạnh 3→1 nghĩa là gì?
Đã đảo chiều ý nghĩa của cạnh.
Không có yêu cầu học đồng thời.
Đúng. Mũi tên chỉ phần tiên quyết.
Cạnh đang biểu diễn quan hệ phụ thuộc.
Lời giải
Cạnh i→j được định nghĩa là i cần j trước. Thay i=3,j=1 suy ra 1 phải hoàn thành trước khi học 3.
Bài luyện
Trong DFS có hướng, gặp cạnh từ u tới v có state[v]=1 cho biết điều gì?
Đúng. Ghép nhánh hiện tại với cạnh quay về tạo vòng.
State 1 là đang duyệt, không phải đã xong.
Trạng thái không đổi hướng của đồ thị.
Đang xét chính cạnh u→v.
Lời giải
v đang nằm trong active. Đã có đường từ v qua nhánh DFS đến u; cạnh u→v khép đường ấy thành chu trình có hướng.
Bài luyện
Vì sao 0→1,0→2,2→1 chưa tạo chu trình?
Ba đỉnh có thể tạo chu trình nếu nối vòng.
Cạnh tới đỉnh đang duyệt có thể tạo chu trình.
Chu trình không cần khuyên.
Đúng. Hai đường cùng tới một đỉnh không tự tạo vòng có hướng.
Lời giải
Các cạnh đều kết thúc ở 1 hoặc đi từ 0 tới 2. Không có cạnh đi ra từ 1, nên không thể khép vòng. Một đỉnh đã xong state=2 có thể được tới từ nhánh khác mà không có chu trình.
Đang học