Các bài toán áp dụng dfs cơ bản
Bài toán và phương pháp tìm kiếm lời giải [Thuật toán BFS, DFS] Show Nội dung Bài toán và phương pháp tìm kiếm lời giải: - Tổng quan về tìm kiếm - Không gian trạng thái - Biểu diễn các bài toán trong không gian trạng thái - Đồ thị tìm kiếm và cây tìm kiếm - Các chiến lược tìm kiếm trên không gian trạng thái - Tìm kiếm trên không gian trạng thái Cụ thể hơn, các bạn hãy theo dõi video dưới đây. Trong cấu trúc dữ liệu và giải thuật thì đồ thị là một dạng cấu trúc dữ liệu cơ bản và có ứng dụng rất rộng rãi. Nhiều hệ thống phức tạp có thể được mô phỏng như là một đồ thị, ví dụ như hệ thống giao thông, hệ thống mạng, hệ thống truyền tải điện. Trong đó, hai thuật toán duyệt đồ thị theo chiều rộng (BFS) và chiều sâu (DFS) là hai thuật toán cơ bản nhất của đồ thị. Các thuật toán này giúp chúng ta “đến thăm” tất cả các cạnh và các đỉnh của đồ thị trong thời gian tối thiểu. Trong bài viết này, tôi muốn đi sâu hơn bằng cách giới thiệu những ứng dụng của hai thuật toán này trong lập trình. Phần cuối bài, tôi sẽ liên hệ các thuật toán này với một trò chơi Dò mìn (Minesweeper) một trò cổ điền của Microsoft, và giới thiệu với các bạn bản Dò mìn remake của tôi. 2. Bài toán có sử dụng BFS2.1 Kiểm tra một đồ thị là phân đôi (bi-partite)Một đồ thị là phân đôi, hay hai phía là một đồ thị \(G = (V, E)\) trong đó tập hợp các đỉnh có thể được chia làm hai tập hợp không giao nhau sao cho các đỉnh ở cùng nhóm không kề nhau. Có rất nhiều tình huống thực tế có thể mô phỏng bằng đồ thị phân đôi. Ví dụ, muốn biểu diễn mối quan hệ giữa một nhóm học sinh và một nhóm các trường học, ta có thể dùng một đồ thị với mỗi một học sinh và mỗi trường học là một đỉnh. Giữa một người \(A\) và một trường \(X\) sẽ có một cạnh nếu như \(A\) đã hoặc đang đi học ở trường \(X\). Kiểu đồ thị này sẽ là một đồ thị phân đôi, với một nhóm đỉnh là người và nhóm kia là trường; sẽ không có cạnh nối giữa hai người hoặc giữa hai trường. Một tính chất thú vị của đồ thị phân đôi là, ta có thể tô màu các đỉnh đồ thị với hai màu sao cho không có hai đỉnh nào cùng màu kề nhau. Đồ thị phân đôi Muốn kiểm tra một đồ thị là phân đôi hay không, ta có thể dùng BFS để tô màu đồ thị với hai màu, đen và đỏ.
Ta có thể thâý, bằng cách thêm một array để tô màu các đỉnh vào BFS, ta có thể kiểm tra xem một đồ thị có phải phân đôi không. Ngoài ra, ta có thể rút ra nhận xét, các đồ thị có vòng chẵn là đồ thị hai phiá, còn vòng lẻ thì không. 2.2 Tìm đường ngắn nhất trong đồ thị không có trọng số (Single source Shortest path in an unweighted graph)Bài toán tìm đường ngắn nhất trong đồ thị là một dạng bài toán rất rộng, với rất nhiều thuật toán nổi tiếng áp dụng cho các loại đồ thị khác nhau. Trong thực tế, các thuật toán tìm đường ngắn nhất có rất nhiều ứng dụng trong công nghệ, ví dụ như tìm đường ngắn nhất để truyền tín hiệu trong mạng internet. Trong phần nay, tôi sẽ đề cập đến bài toán tìm đường ngắn nhất từ một đỉnh đến nhiều đỉnh trong đồ thị với các cạnh không có trọng số. Đường ngắn nhất từ một đỉnh đến một đỉnh khác là đường đi từ đỉnh thứ nhất đến đỉnh thứ hai sao cho tổng độ dài (weight) của đoạn đường đó là nhỏ nhất. Trong đồ thị không trọng số với các cạnh có độ dài bằng nhau, đường ngắn nhất là đường đi qua ít cạnh nhất. Thuật toán BFS xuất phát từ đỉnh \(s\) sẽ giúp ta tìm đường ngắn nhất từ \(s\) đến tất cả các đỉnh liên thông với \(s\). Muốn biết tại sao BFS lại có thể tìm đựơc đường đi qua ít cạnh nhất từ đỉnh này đến đỉnh khác trong đồ thị, ta quay trở lại khái niệm của BFS một chút. Trong BFS, từ một đỉnh hiện tại, ta luôn đi thăm tất cả các đỉnh kề với nó trước, sau đó thăm tất cả các đỉnh cách nó một đỉnh, rồi các đỉnh cách nó hai đỉnh… vân vân. Như vậy, nếu từ một đỉnh \(u\) ta chạy BFS, quãng đường đên đỉnh \(v\) luôn là quãng đường đi qua ít cạnh nhất.
Tìm đường ngắn nhất từ 1 với BFS
3. Bài toán có sử dụng DFS3.1 Tìm vòng trong đồ thị vô hướngTa có thể lợi dụng tính chất duyệt chiều sâu của DFS để tìm xem đồ thị có vòng không. Trong đồ thị, vòng là một đường đi với mỗi cạnh chỉ đựơc đi qua một lần và đỉnh xuất phát cũng là đỉnh cuối cùng. Với đồ thị vô hướng, vòng tồn tại khi và chỉ khi, từ một đỉnh, ta gặp lại một đỉnh đã thăm mà không phải đỉnh trước của đỉnh đó.
Ta có thể viết thuật toán như sau:
3.2 Tìm vòng (cycle) trong đồ thị có hướngGiống với đồ thị vô hướng, ta cũng có thể dùng DFS để xác định đồ thị cớ hướng có vòng không. Tuy nhiên, trong đồ thị có hướng, điều kiện có vòng khác với vô hướng. Giả sử có đồ thị \(1 \rightarrow 2 \rightarrow 3; 1 \rightarrow 3 \). Ta duyệt DFS xuất phát từ \(1\) và đi theo đường \(1 \rightarrow 2 \rightarrow 3\). Đến đây, ta quay ngược lại và đi theo đường \(1 \rightarrow 3\). Mặc dù từ đỉnh \(1\) ta quay lại đỉnh \(3\) là đỉnh đã thăm và \(3\) không phải đỉnh trước của \(1\), nhưng rõ ràng đồ thị này không hề có vòng. Ví dụ về vòng trong đồ thị có hướng Muốn kiểm tra vòng trong đồ thị có hướng với DFS, ta cần phải mở rộng DFS, tăng số trạng thái của một đỉnh lên 3 chứ không phải 2. Cụ thể như sau:
Trong duyệt thuật toán trên với các đồ thị sau để thâý rõ hơn. Ta xuất phát từ \(1\). Đồ thị thứ nhất không có vòng, đồ thị thứ hai có, khi mà từ đinh \(3\) chúng ta quay lại \(1\) vẫn còn ở trạng thái ‘chưa xong’. Ví dụ về trường hợp không có vòng Ví dụ về trường hợp có vòng 4. Case study: Dò mìn (Minesweeper)
Dò mìn
Tham khảo[1] Cormen, Thomas H., Leiserson, Charles E., Rivest,Ronald L., and Stein, Clifford. “Introduction to Algorithms”, MIT Press(2009) |