Depth First Search hay DFS là một giải thuật cơ bản và quan trọng trong lý thuyết đồ thị. DFS là nền tảng để xây dựng nên các giải thuật quan trọng khác như tìm đường đi, tìm thành phần liên thông, cây khung, chu trình, luồng, cặp ghép, …
Giải thuật DFS tìm ra các đường đi theo thứ tự từ đỉnh nguồn $u$ tới mọi đỉnh khác. Trên đồ thị cây, giữa 2 đỉnh bất kì chỉ có 1 đường đi đơn duy nhất do đó DFS tìm ra đường đi ngắn nhất giữa 2 đỉnh trên cây.
Độ phức tạp của giải thuật DFS là $O(m + n)$ với $n$ là số đỉnh và $m$ là số cạnh trên đồ thị.
Giải thuật DFS
Ý tưởng đơn giản của DFS là duyệt lần lượt từng đỉnh trên đồ thị, tới đỉnh nào đánh dấu lại đỉnh đó đã được duyệt và tiếp tục duyệt các đỉnh liền kề tiếp theo, quay lui khi đã duyệt xong các đỉnh.
Hiện thực giải thuật bằng kỹ thuật đệ quy quay lui đơn giản hoặc sử dụng stack.
Implementation
Hiện thực đơn giản nhất cho DFS như sau:
vector<vector<int>> adj; // graph represented as an adjacency list
int n; // number of vertices
vector<bool> visited;
void dfs(int v) {
visited[v] = true;
for (int u : adj[v]) {
if (!visited[u])
dfs(u);
}
}
Mở rộng DFS: lưu thêm thời gian thăm đỉnh vào / ra dùng cho việc kiểm tra thứ tự thăm đỉnh ở một số giải thuật khác.
vector<vector<int>> adj; // graph represented as an adjacency list
int n; // number of vertices
vector<int> color;
vector<int> time_in, time_out;
int dfs_timer = 0;
void dfs(int v) {
time_in[v] = dfs_timer++;
color[v] = 1;
for (int u : adj[v])
if (color[u] == 0)
dfs(u);
color[v] = 2;
time_out[v] = dfs_timer++;
}
Ứng dụng của DFS
Một số ứng dụng của giải thuật DFS:
- Tìm đường đi từ đỉnh nguồn $u$ tới mọi đỉnh trong đồ thị.
- Kiểm tra cha của các đỉnh trên đồ thị cây: sử dụng thời gian duyệt đỉnh vào/ra trên cây khi duyệt để xác định cặp đỉnh $u,v$ có quan hệ tiền bối / hậu bối của nhau hay không. Chi tiết có thể xem trong bài viết tìm cha chung gần nhất trên cây LCA.
- Tìm tổ tiên chung gần nhất (LCA: lowest common ancestor) trên cây.
- Topological sorting.
- Kiểm tra và tìm chu trình trong đồ thị.
- Tìm thanh phần liên thông mạnh trong đồ thị có hướng.
- Tìm cầu trong đồ thị vô hướng.
Practice Problems
- SPOJ: ABCPATH
- SPOJ: EAGLE1
- Codeforces: Kefa and Park
- Timus:Werewolf
- Timus:Penguin Avia
- Timus:Two Teams
- SPOJ - Ada and Island
- UVA 657 - The die is cast
- SPOJ - Sheep
- SPOJ - Path of the Rightenous Man
- SPOJ - Validate the Maze
- SPOJ - Ghosts having Fun
- Codeforces - Underground Lab
- DevSkills - Maze Tester
- DevSkills - Tourist
- Codeforces - Anton and Tree
- Codeforces - Transformation: From A to B
- Codeforces - One Way Reform
- Codeforces - Centroids
- Codeforces - Generate a String
- Codeforces - Broken Tree
- Codeforces - Dasha and Puzzle
- Codeforces - Making genome In Berland
- Codeforces - Road Improvement
- Codeforces - Garland
- Codeforces - Labeling Cities
- Codeforces - Send the Fool Futher!
- Codeforces - The tag Game
- Codeforces - Leha and Another game about graphs
- Codeforces - Shortest path problem
- Codeforces - Upgrading Tree
- Codeforces - From Y to Y
- Codeforces - Chemistry in Berland
- Codeforces - Wizards Tour
- Codeforces - Ring Road
- Codeforces - Mail Stamps
- Codeforces - Ant on the Tree
- SPOJ - Cactus
- SPOJ - Mixing Chemicals