Tìm đường thoát khỏi khu rừng¶
Đôi khi vì quá đam mê cái gì đó mà ta bị lầm đường lạc trôi or lạc lối. Nếu lỡ bị hút vào trận đồ và cảm thấy tuyệt vọng không lối thoát, bạn hãy học Tin học, nó sẽ cho bạn ánh sáng cuối đường hầm, giống như nhà thám hiểm trong bài toán sau đây. Anh đã sử dụng thuật toán DFS để thoát khỏi khu rừng.
Khái quát về bài toán¶
Bài toán này1 dùng để minh họa cho thuật toán tìm đường cơ bản là DFS. Nguyên tắc cơ bản của DFS là vươn xa đến tận cùng.
Yêu cầu¶
Cho một khu rừng được mô phỏng bằng ma trận hàng và cột, trong đó những ô mang ký tự 'O'
là đi vào được, còn những ô mang ký tự 'X'
là cạm bẫy, không đi vào được.
Nhà thám hiểm đang đứng tại ô mang ký tự 'E'
và phải tìm đường thoát ra khỏi khu rừng. Cụ thể hơn, anh có thể di chuyển qua ô khác theo một trong bốn hướng: lên, xuống, trái và phải, và tìm cách đến được bìa rừng, chính là các cạnh biên của ma trận.
Input¶
5 5
XXXXX
XEOOX
XXXOX
XOOOX
XOXXX
Output¶
1 1
1 2
1 3
2 3
3 3
3 2
3 1
4 1
Giải thích¶
Trong Input, dòng đầu tiên là kích thước hàng và cột của ma trận; các dòng tiếp theo là các hàng của ma trận, mỗi hàng là một chuỗi ký tự để mô tả khu rừng.
Output là đường đi từ ô của nhà thám hiểm ra đến bìa rừng.
Hình 1. Minh họa input và output
Cách giải đề xuất¶
Ý tưởng chính¶
Nhà thám hiểm sẽ sử dụng tuyệt chiêu phân thân chi thuật, xuất ra một bản sao của cơ thể để đi thử qua các ô khác cho đến khi ra đến bìa rừng.
Lúc đến bìa rừng thì ghi nhận ô đang đứng là ô đích, rồi thực hiện truy ngược về ô xuất phát ban đầu.
Theo ý tưởng này, ta áp dụng thuật toán DFS như sau:
-
Xây dựng hàm đệ quy có tham số là ô mà nhà thám hiểm đang đứng, đặt là ô
current
. -
Ban đầu, xuất phát từ ô có ký tự E, đi thử qua 1 trong 4 ô liền kề.
-
Giả sử đi hướng lên vào ô bên trên, đặt là ô
next
. Nếu ônext
chưa ghé thăm và không có cạm bẫy (ký tự'X'
), nghĩa là đi vào được, thì đánh dấu đã ghé thăm ônext
, rồi gọi đệ quy với tham số là ônext
, tức vai trò của ônext
trở thànhcurrent
để chuẩn bị cho bước duyệt tiếp theo. -
Trường hợp cơ sở của hàm đệ quy là ô
current
nằm ngay trên đường biên của ma trận khu rừng, tương ứng với hàng đầu hoặc hàng cuối hoặc cột đầu hoặc cột cuối.
Khởi tạo¶
-
Xác định vị trí xuất phát của nhà thám hiểm.
-
Khởi tạo 4 nước đi ứng với 4 hướng: lên, xuống, trái và phải.
-
Khởi tạo ma trận
trace
với mọi ô đều là-1
, nghĩa là chưa ghé thăm. Khi ô nào đi vào được, ta đánh dấu bằng một con số kết hợp từ chỉ số hàng và chỉ số cột của ô đó. Phép tính kết hợp sẽ đề cập ở bên dưới.
Thực hiện DFS¶
-
Trường hợp cơ sở: ô
current
nằm ngay trên đường biên của ma trận. Tại đây, ta ghi nhận ô đích bằng biếnfinish
. -
Trường hợp đệ quy:
Duyệt 4 nước đi (mảng
step
), tức thử di chuyển qua các ô liền kề với ôcurrent
. Nếu ô liền kề thỏa các điều kiện:- Vẫn còn trong phạm vi khu rừng,
- Không có bẫy,
- Chưa ghé thăm.
thì đánh dấu ô liền kề này bằng mảng
trace
, rồi gọi đệ quy với tham số là nó (ô liền kề).Vì mỗi phần tử của mảng
trace
chỉ có thể chứa một số nguyên duy nhất, nên ta sử dụng chiêu thức lưỡng long hợp thể, như code dưới đây, để kết hợp chỉ số hàng và chỉ số cột của thành một số nguyên. Đến phần output, ta sẽ giải nén trở lại.
Output đường đi kết quả¶
Trong hàm đệ quy, ta đã dùng biến finish
để ghi nhận tọa độ của ô đích ở bìa rừng. Bây giờ, dựa vào mảng trace
, ta cho finish
lui dần về ô xuất phát ban đầu của nhà thám hiểm.
Mặt khác, do ở trên đã lưỡng long hợp thể, nên tại đây ta giải nén bằng cách sử dụng phép chia lấy phần dư và thương, ứng với chỉ số hàng và chỉ số cột.
Toàn bộ chương trình¶¶
Code đầy đủ được đặt tại GitHub.
-
Bài toán do chủ thớt tham khảo trên Internet nhưng không còn nhớ lấy từ trang web nào. ↩