Đồ thị ví dụ: Hình 1: Đồ thị vô hướng có 8 đỉnh Với đồ thị trên, file dữ liệu biểu diễn (graph_dfs1.txt) ở dạng ma trận kề sẽ là: 8 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 Sau đây là chương trình (graph_dfs1.cpp) đọc đồ thị biểu diễn ở dạng ma trận kề (từ bàn phím hoặc từ file), sau đó duyệt đồ thị bằng thuật toán duyệt ưu tiên chiều sâu DFS. // Graph traversal using DFS // Author: Nguyen Huu Tuan, huu-tuan.nguyen@vimaru.edu.vn // Lecturer at the FIT, Vietnam Maritime University // Date: 14/10/2015 // Require: C++ 11 supported compiler #include <iostream> // for cin, cout #include <fstream> // for file stream #include <vector> // for vector using namespace std; // cai dat DFS bang ma tran ke void DFS(vector<vector<int>> & vvi); // duyet do theo chieu sau void DFS_visit(vector<vector<int>> & vvi, int v); // duyet do theo chieu sau bat dau tu dinh v void print_path(int v, int u); 1
int TIME; vector<int> visited; // mang danh dau da den tham chua vector<int> p; // mang luu dinh truoc vector<int> d; // mang luu thu tu den tham int WHITE = 0; // chua tham int GREY = 1; // dang tham int BLACK = 2; // da tham xong int main(int argc, char * argv[]) // argc: argument count, argv: argument values int n; vector<vector<int>> vvi(n, vector<int>(n, 0)); int i, j; if (argc > 1) if (atoi(argv[1]) == 0) cout << "Nhap so dinh cua do thi n="; cin >> n; for (j = i + 1; j < n; j++) cout << "Nhap a[" << i << "][" << j << "]="; cin >> vvi[i][j]; else if (argc == 3) ifstream fin(argv[2]); // mo file fin >> n; for (j = 0; j < n; j++) fin >> vvi[i][j]; fin.close(); // dong file DFS(vvi); // duyet do thi for (auto & it : p) // in mang p cout << it << ", "; 2
cout << endl; for (auto & it : d) // in mang d cout << it << ", "; else cout << "Chay chuong trinh nhu sau:<ten chuong trinh> <0:nhap tu ban phim,1: nhap tu file> <ten file>"; return 0; void DFS(vector<vector<int>> & vvi) TIME = 1; int n = vvi.size(); // dinh cua do thi // khoi tao p = vector<int>(n, -1); d = vector<int>(n, -1); visited = vector<int>(n, WHITE); for (int v = 0; v < n; v++) if (WHITE == visited[v]) // v chua duoc tham DFS_visit(vvi, v); void DFS_visit(vector<vector<int>> & vvi, int v) visited[v] = GREY; int n = vvi.size(); d[v] = TIME++; // thu tu den tham dinh v for (int u = 0; u < n; u++) // xet cac dinh ke voi v if ((vvi[v][u] > 0) && (WHITE == visited[u])) // va chua duoc tham p[u] = v; // v la dinh truoc khi den u DFS_visit(vvi, u); visited[v] = BLACK; Lệnh để chạy chương trình trên với file dữ liệu ví dụ là: graph_dfs1 1 graph_dfs1.txt. Sau đây là ví dụ (graph_dfs2.cpp) duyệt đồ thị theo chiều sâu để đếm số thành phần liên thông của đồ thị, in ra các đỉnh thuộc về các thành phần liên thông và in ra đường đi từ một đỉnh tới một đỉnh khác. Để thực hiện điều này ta sẽ thay đổi mã lệnh của chương trình graph_dfs1: trong hàm DFS() mỗi lần gọi tới DFS_visit() ta sẽ có 1 thành phần liên thông và lưu vào biến comp (tăng lên 1). Mảng d sẽ được sử dụng để đánh dấu các đỉnh thuộc về cùng một thành phần liên thông. Tiếp đến để in đường đi ta sẽ dùng hàm đệ qui print_path(v, u), ban đầu in đường đi từ v tới p[u], sau đó in u. 3
// Graph traversal using DFS // Counting connected components of a graph and finding vertices of each component // And print path between two vertices // Author: Nguyen Huu Tuan, huu-tuan.nguyen@vimaru.edu.vn // Lecturer at the FIT, Vietnam Maritime University // Date: 14/10/2015 // Require: C++ 11 supported compiler #include <iostream> // for cin, cout #include <fstream> // for file stream #include <vector> // for vector using namespace std; // cai dat DFS bang ma tran ke void DFS(vector<vector<int>> & vvi); // duyet do theo chieu sau void DFS_visit(vector<vector<int>> & vvi, int v); // duyet do theo chieu sau bat dau tu dinh v void print_path(int v, int u); int TIME; vector<int> visited; // mang danh dau da den tham chua vector<int> p; // mang luu dinh truoc vector<int> d; // mang luu thu tu den tham int WHITE = 0; // chua tham int GREY = 1; // dang tham int BLACK = 2; // da tham xong int comp = 0; // dem do thanh phan lien thong int main(int argc, char * argv[]) // argc: argument count, argv: argument values int n; vector<vector<int>> vvi(n, vector<int>(n, 0)); int i, j; if (argc > 1) if (atoi(argv[1]) == 0) cout << "Nhap so dinh cua do thi n="; cin >> n; for (j = i + 1; j < n; j++) cout << "Nhap a[" << i << "][" << j << "]="; cin >> vvi[i][j]; 4
else if (argc == 3) ifstream fin(argv[2]); // mo file fin >> n; for (j = 0; j < n; j++) fin >> vvi[i][j]; fin.close(); // dong file endl; else DFS(vvi); // duyet do thi cout << "So thanh phan lien thong cua do thi la: " << comp << endl; for (int i = 0; i < comp; i++) // in thanh phan lien thong thu i cout << "Cac dinh thuoc thanh phan lien thong thu " << i << ":" << for (int v = 0; v < n; v++) if (d[v] == i + 1) cout << v << ", "; cout << endl; print_path(0, 2); // in duong di tu dinh 0 toi dinh 2 cout << "Chay chuong trinh nhu sau:<ten chuong trinh> <0:nhap tu ban phim,1: nhap tu file> <ten file>"; return 0; void DFS(vector<vector<int>> & vvi) TIME = 1; int n = vvi.size(); // dinh cua do thi // khoi tao p = vector<int>(n, -1); d = vector<int>(n, -1); visited = vector<int>(n, WHITE); 5
for (int v = 0; v < n; v++) if (WHITE == visited[v]) // v chua duoc tham comp++; // tang so thanh phan lien thong len 1 DFS_visit(vvi, v); void DFS_visit(vector<vector<int>> & vvi, int v) visited[v] = GREY; int n = vvi.size(); d[v] = comp; // dinh v thuoc ve thanh phan lien thong thu comp for (int u = 0; u < n; u++) // xet cac dinh ke voi v if ((vvi[v][u] > 0) && (WHITE == visited[u])) // va chua duoc tham p[u] = v; // v la dinh truoc khi den u DFS_visit(vvi, u); visited[v] = BLACK; void print_path(int v, int u) if (p[u] == v) cout << v << "->" << u; else print_path(v, p[u]); cout << "->" << u; Lưu ý chạy chương trình từ giao diện console (dòng lệnh) và phải có file dữ liệu cho phần nhập từ file. Dịch bằng Orwell DevCpp (http://sourceforge.net/projects/orwelldevcpp/files/portable%20releases/). Các bài tập khác các bạn có thể làm để luyện tập để áp dụng DFS: + Kiểm tra có tồn tại chu trình xuất phát từ một đỉnh hay không? + Sắp xếp topo 6