Duyệt theo chiều sâu¶
Tóm lược nội dung
Bài này trình bày thuật toán duyệt đồ thị theo chiều sâu (DFS) và cách cài đặt bằng ngôn ngữ Python.
Khái quát¶
Duyệt đồ thị theo chiều sâu, gọi tắt là DFS, là thuật toán duyệt đồ thị:
Hoạt động theo nguyên tắc đi sâu nhất có thể theo mỗi nhánh trước khi quay lui.
- Bắt đầu từ một đỉnh bất kỳ, tạm gọi là đỉnh start.
- Sau đó ghé thăm một trong các đỉnh kề của start, tạm gọi là đỉnhu.
- Tiếp tục ghé thăm một trong các đỉnh kề của u, tạm gọi là đỉnhv.
- Lặp lại quá trình trên cho đến khi không còn đỉnh kề nào chưa ghé thăm.
- Quay lui để ghé thăm các đỉnh kề khác.
Nói cách khác, DFS ưu tiên duyệt các đỉnh ở xa nhất trước, sau đó mới đến các đỉnh ở gần hơn.
Ứng dụng¶
DFS được áp dụng phổ biến cho các bài toán như:
- Tìm kiếm đường đi trong mê cung.
- Kiểm tra tính liên thông của đồ thị.
- Tìm kiếm bạn bè trên mạng xã hội.
- Tô màu đồ thị.
Các bước thực hiện¶
Để thực hiện thuật toán DFS, ta có thể sử dụng kỹ thuật đệ quy hoặc cấu trúc ngăn xếp.
Bài học này chỉ đề cập cách sử dụng ngăn xếp.
Các bước thực hiện như sau:
Buớc 1: Đưa đỉnh start vào ngăn xếp.
Bước 2: Lặp lại các thác tác sau cho đến khi ngăn xếp không còn phần tử:
- Lấy đỉnh trên cùng ra khỏi ngăn xếp, đặt là đỉnh current.
- 
Duyệt các đỉnh vkề với đỉnhcurrentvừa lấy ra:Nếu vchưa được ghé thăm thì: - Đánh dấu đỉnhvđã ghé thăm. - Đưa đỉnhvvào ngăn xếp. - Thực hiện các công việc cần thiết với đỉnhv.
Ví dụ:
Gọi Thành phố Hồ Chí Minh là đỉnh start.
Theo DFS, sau khi duyệt đỉnh start, ta sẽ duyệt đỉnh đầu tiên kề với đỉnh start, giả sử là 'Đồng Nai'.
Ứng với đỉnh 'Đồng Nai', ta sẽ duyệt đỉnh đầu tiên kề với Đồng Nai, giả sử là 'Bình Phước'.
Ứng với đỉnh 'Bình Phước', ta sẽ duyệt đỉnh đầu tiên kề với Bình Phước, giả sử là 'Lâm Đồng'.
Cứ như thế cho đến khi đến được đỉnh cuối cùng hoặc không còn đỉnh kề nào chưa ghé thăm.
Ngoài ra, để tránh lặp lại, ta cần đánh dấu các đỉnh đã ghé thăm.
Bài toán minh hoạ¶
Yêu cầu¶
Tìm đường đi giữa hai đỉnh trong đồ thị bằng cách áp dụng DFS.
Input¶
Output¶
Giải thích¶
Input:
- Dòng đầu tiên gồm các đỉnh của đồ thị.
- Các dòng tiếp theo mô tả các cạnh của đồ thị.
- Hai dòng cuối cùng là hai đỉnh cần tìm đường đi.
Đồ thị có thể được phác hoạ như sau:
Output:
Đường đi từ đỉnh 0 đến đỉnh 5 là: 0 -> 2 -> 4 -> 5
Cách giải đề xuất¶
Khai báo biến chứa input¶
Khai báo biến data chứa dữ liệu đầu vào như bài trước.
Khởi tạo danh sách kề¶
Viết hàm init_adjacency_list() để khởi tạo danh sách kề từ input như bài trước.
Khởi tạo cho hàm DFS¶
Hàm dfs() dùng để tìm đường đi giữa hai đỉnh trong đồ thị bằng DFS, gồm ba tham số:
- adj_list: danh sách kề của đồ thị.
- start: đỉnh bắt đầu.
- finish: đỉnh kết thúc.
Hàm này trả về mảng trace dùng để truy vết đường đi. Nếu không có đường đi, hàm trả về mảng rỗng hoặc None.
Trước khi thực hiện duyệt DFS, ta cần khởi tạo các biến sau:
- 
stack: ngăn xếp dùng để lưu các đỉnh trong khi duyệt DFS.Ban đầu, ngăn xếp chứa đỉnh start.
- 
Thay vì dùng biến visited, ta dùng biếntraceđể vừa đánh dấu các đỉnh đã ghé thăm, vừa lưu vết nhằm truy ngược đường đi sau này.Cụ thể, trace[v] = unghĩa là trước đỉnhvlà đỉnhu.Ví dụ: trace[start] = Nonenghĩa là đỉnhstartkhông có đỉnh nào nằm trước nó.trace[5] = 3nghĩa là trước đỉnh5là đỉnh3.Biến tracevừa dùng để đánh dấu các đỉnh đã ghé thăm, vừa dùng để truy vết đường đi.Biến tracecó thể là kiểulisthoặcdictionary. Trong bài này, ta sử dụng kiểudictionaryđể tiện cho việc lưu trữ và truy xuất.
Thực hiện DFS¶
Buớc 1: Đưa đỉnh start vào ngăn xếp.
Đã thực hiện ở bước khởi tạo.
Bước 2:
Duyệt ngăn xếp cho đến khi ngăn xếp không còn phần tử nào nữa:
- Lấy đỉnh trên cùng ra khỏi ngăn xếp, đặt là đỉnh current.
- 
Duyệt các đỉnh vkề với đỉnhcurrentvừa lấy ra:Nếu vchưa được ghé thăm thì: - Đánh dấu đỉnhvbằng mảngtrace:trace[v] = current. - Đưa đỉnhvvào ngăn xếp.
Truy vết đường đi¶
Hàm get_path() dùng để truy vết đường đi dựa trên mảng trace.
Cụ thể, hàm này dùng biến tạm node để di chuyển ngược từ đỉnh finish về đỉnh trước đó, dựa trên trace[finish], và dần dần về đỉnh start.
Hàm này trả về mảng path chứa đường đi.
In kết quả¶
Trong chương trình chính, ta gọi các hàm vừa viết và in kết quả ra màn hình.
Nhận xét¶
- 
DFS không tìm ra đường đi ngắn nhất, mà chỉ tìm đường liên thông, nghĩa là có đường đi hoặc không có đường đi từ đỉnh này sang đỉnh khác. 
- 
Có thể có nhiều đường đi, nhưng DFS luôn trả về đường đi có thứ tự từ điển nhỏ nhất. 
Mã nguồn¶
Code đầy đủ được đặt tại:
Some English words¶
| Vietnamese | Tiếng Anh | 
|---|---|
| duyệt theo chiều sâu | depth first search (DFS) |