Tìm đường cho robot trong mê cung¶
Robot là loại đồ chơi thời thượng hiện nay. Trào lưu robot có vẻ đang lên khi thầy thầy chơi robot, trò trò chơi robot. Mặc dù không phải cuộc thi robot nào của học sinh phổ thông cũng đều ứng dụng thuật toán tìm đường, đây vẫn là một thuật toán thú vị nên tìm hiểu khi chơi robot.
Đu theo trend này, bài viết mô tả bài toán tìm đường di chuyển của robot di chuyển trong mê cung. Đây cũng là ví dụ minh họa cho thuật toán BFS, mà giang hồ gọi thuật toán loang.
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à BFS. Nguyên tắc cơ bản của BFS là xét hết các phần tử của thế hệ kế cận, rồi mới đến các thế hệ xa hơn, hoặc xoắn ốc từ trong ra ngoài, từ nhỏ đến lớn, từ hẹp đến rộng.
Yêu cầu¶
Cho một mê cung được mô phỏng bằng ma trận, hàng và cột đánh chỉ số bắt đầu từ 1. Trong đó những ô có giá trị 0
thì đi vào được, còn những ô có giá trị 1
thì không được.
Robot 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. Hãy tìm đường để robot di chuyển từ ô có tọa độ (r1, c1) đến ô (r2, c2), hai tọa độ này đều được cho trước.
Input¶
4 7 1 3 2 6
1001000
0010100
0000000
1101000
Output¶
1 3
1 2
2 2
3 2
3 3
3 4
3 5
3 6
2 6
Giải thích¶
Trong Input, dòng dầu tiên gồm 6 số là:
- 4 hàng và 7 cột của ma trận, đánh chỉ số từ 1.
- [1,3] là ô xuất phát và [2,6] là ô kết thúc.
Output là đường đi từ ô xuất phát đến ô kết thúc.
Hình 1. Minh họa input và output
Cách giải đề xuất¶
Ý tưởng chính¶
Dựa theo thuật toán BFS, ta thực hiện loang như sau:
-
Xuất phát từ ô
start
, lần lượt xét 4 ô liền kề, ô nào robot có thể đi vào được thì đánh dấu (để truy vết đường đi sau này) và nạp vào hàng đợiq
(để chờ đến lượt xét các ô liền kề với nó). -
Lặp lại thao tác trên cho đến khi hàng đợi
q
không còn ô nào để xét hoặc chạm đến ôfinish
.
Khởi tạo¶
Khởi tạo mảng hai chiều trace
để đánh dấu các ô đã xét và dùng cho việc xuất đường đi kết quả.
Các phần tử trong mảng trace
đều được đánh dấu là 'N', nghĩa là chưa đi vào (Not yet). Riêng ô start
được đánh dấu là 'S'.
Thực hiện BFS¶
-
Khai báo hàng đợi
q
và nạp ôstart
vào hàng đợi. -
Sử dụng vòng lặp while để duyệt các phần tử trong hàng đợi.
- Trong vòng lặp, biến
current
dùng để xét phần tử đầu tiên của hàng đợi. - Một trong hai điều kiện để ngắt vòng lặp là ô
current
trùng với ôfinish
, nghĩa là đã tới đích. Điều kiện còn lại là hàng đợi không còn phần tử nào để xét nữa.
- Trong vòng lặp, biến
-
Lần lượt xét bốn ô liền kề với ô
current
là: trên, dưới, trái và phải. Đầu tiên, xét ô-bên-trên, có những điều kiện cần phải đáp ứng như sau:- Thứ nhất, để robot có thể đi lên, thì robot không được nằm trên đường-biên-trên của mê cung, nghĩa là chỉ số hàng của
current
phải lớn hơn 1. - Thứ hai, điều kiện tiếp theo là ô-bên-trên phải đi vào được, tức ô có giá trị 0.
- Thứ ba, ô-bên-trên chưa được ghé thăm, tức giá trị tương ứng trong mảng
trace
là'N'
.
Nếu thỏa cả ba điều kiện này, ta nạp ô-bên-trên vào hàng đợi và đánh dấu là 'U', viết tắt của Up.
- Thứ nhất, để robot có thể đi lên, thì robot không được nằm trên đường-biên-trên của mê cung, nghĩa là chỉ số hàng của
-
Thực hiện tương tự cho ba ô liền kề còn lại, thay đổi giá trị tương ứng cho các biến liên quan. Sau đó, ngắt bỏ ô
current
ra khỏi hàng đợi.
Output đường đi kết quả¶
Để xuất đường đi kết quả, ta truy ngược bằng cách cho ô finish
lui dần về ô start
dựa theo mảng trace
. Trong đó, finish
sẽ lùi ngược hướng với ký tự lưu trong trace
. Ví dụ: ký tự lưu trong trace là 'U'
, đi lên, thì finish
sẽ đi xuống.
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. ↩