1 [Lời giải]Bài tập Đồ thị - Bài toán con ngựa Fri Jun 17, 2011 9:47 pm
mrP
Thành viên cao cấp
Trên bàn cờ quốc tế A[1..8, 1..8], giả sử quân mã nằm ở ô (x, y). Cho ô (i, j), hãy sử dụng mô hình đồ thị để xác định cách đi quân mã từ ô (x, y) đên ô (i, j) sao cho tốn ít nước nhất.
Bài này tôi viết hơi dài, mọi người đọc và kiểm tra độ đúng đắn của thuật toán và sửa lại cho ngắn nhé. Bài viết sử dụng thuật toán duyệt theo chiều rộng.
FOR m : = 1 TO 8 DO
FOR n : = 1 TO 8 DO
Đã_xét(a(m, n)) : = 0;
{Viết ngược. Vì đường đi ngắn nhất từ (x, y)→(i, j) cũng chính là đường đi ngắn nhất từ (i, j)→(x, y), cái này liên quan đến output đường đi ở dưới cùng)}
u : = i;
v : = j;
Enqueue (a(u, v), HĐ)
Đã_xét(a(u, v)) : = 1;
WHILE Đã_xét(x, y) ≠ 0 DO
u : = front(HĐ).hàng;
v : = front(HĐ).cột;
DeQueue(HĐ);
{kiểm tra các cách nhảy của ngựa vào ô tiếp theo. Nếu ô đó nằm trong bàn cờ và chưa xét thì cho vào hàng đợi. Gán chỉ số ô tiếp theo bằng chỉ số ô trước nó cộng thêm 1. Có nghĩa là chỉ số của ô sẽ bằng số lần nhảy từ ô xuất phát đến ô đó}
IF ((u ≤ 6 & v ≥ 1) & Đã_xét(a(u + 2, v - 1)) = 0) THEN
Enqueue (a(u + 2, v - 1), HĐ);
Đã_xét(a(u + 2, v - 1) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 6 & v ≤ 7) & Đã_xét(a(u + 2, v + 1)) = 0) THEN
Enqueue (a(u + 2, v + 1), HĐ);
Đã_xét(a(u + 2, v + 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 7 & v ≤ 6) & Đã_xét(a(u + 1, v + 2)) = 0) THEN
Enqueue (a(u + 1, v + 2), HĐ);
Đã_xét(a(u + 1, v + 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 1 & v ≤ 6) & Đã_xét(a(u - 1, v + 2)) = 0) THEN
Enqueue (a(u - 1, v + 2), HĐ);
Đã_xét(a(u - 1, v + 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 2 & v ≥ 7) & Đã_xét(a(u - 2, v + 1)) = 0) THEN
Enqueue (a(u - 2, v + 1), HĐ);
Đã_xét(a(u - 2, v + 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 2 & v ≥ 1) & Đã_xét(a(u - 2, v - 1)) = 0) THEN
Enqueue (a(u - 2, v - 1), HĐ);
Đã_xét(a(u - 2, v - 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 1 & v ≥ 2) & Đã_xét(a(u - 1, v - 2)) = 0) THEN
Enqueue (a(u - 1, v - 2), HĐ);
Đã_xét(a(u - 1, v - 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 7 & v ≥ 2) & Đã_xét(a(u + 1, v - 2)) = 0) THEN
Enqueue (a(u + 1, v - 2), HĐ);
Đã_xét(a(u + 1, v - 2)) : = Đã_xét(a(u, v)) + 1;
{Viết lại đường đi của con mã (viết ngược, nếu muốn viết xuôi, có lẽ đổi vai trò cho chúng ngay từ đầu. Vì đường đi ngắn nhất từ (x y)→(i, j) cũng chính là đường đi ngắn nhất từ (i, j)→(x y))}
k : = Đã_xét (a(x, y));
u : = x;
v : = y;
write(a(u, v);
WHILE k ≠1 DO
IF ((u ≤ 6 & v ≥ 1) & Đã_xét(a(u + 2, v - 1)) = k - 1) THEN k : = k - 1; u0 : = u + 2; v0 : = v - 1;
IF ((u ≤ 6 & v ≤ 7) & Đã_xét(a(u + 2, v + 1)) = k - 1) THEN k : = k - 1; u0 : = u + 2; v0 : = v + 1;
IF ((u ≤ 7 & v ≤ 6) & Đã_xét(a(u + 1, v + 2)) = k - 1) THEN k : = k - 1; u0 : = u + 1; v0 : = v + 2;
IF ((u ≥ 1 & v ≤ 6) & Đã_xét(a(u - 1, v + 2)) = k - 1) THEN k : = k - 1; u0 : = u - 1; v0 : = v + 2;
IF ((u ≥ 2 & v ≥ 7) & Đã_xét(a(u - 2, v + 1)) = k - 1) THEN k : = k - 1; u0 : = u - 2; v0 : = v + 1;
IF ((u ≥ 2 & v ≥ 1) & Đã_xét(a(u - 2, v - 1)) = k - 1) THEN k : = k - 1; u0 : = u - 2; v0 : = v - 1;
IF ((u ≥ 1 & v ≥ 2) & Đã_xét(a(u - 1, v - 2)) = k - 1) THEN k : = k - 1; u0 : = u - 1; v0 : = v - 2;
IF ((u ≤ 7 & v ≥ 2) & Đã_xét(a(u + 1, v - 2)) = k - 1) THEN k : = k - 1; u0 : = u + 1; v0 : = v - 2;
u : = u0;
v : = v0;
write(a(u, v));
- May mà viết sẵn ở trong word, chẳng biết bấm chỉnh sửa gì mà toàn bộ dấu + ("cộng") bị mất hết. Mấy bài trung tố, hậu tố tôi đọc cũng bị mất hết dấu cộng. Viết ở Firefox thì mới thêm được bảng, nhưng lại gặp rắc rối này.
Bài này tôi viết hơi dài, mọi người đọc và kiểm tra độ đúng đắn của thuật toán và sửa lại cho ngắn nhé. Bài viết sử dụng thuật toán duyệt theo chiều rộng.
FOR m : = 1 TO 8 DO
FOR n : = 1 TO 8 DO
Đã_xét(a(m, n)) : = 0;
{Viết ngược. Vì đường đi ngắn nhất từ (x, y)→(i, j) cũng chính là đường đi ngắn nhất từ (i, j)→(x, y), cái này liên quan đến output đường đi ở dưới cùng)}
u : = i;
v : = j;
Enqueue (a(u, v), HĐ)
Đã_xét(a(u, v)) : = 1;
WHILE Đã_xét(x, y) ≠ 0 DO
u : = front(HĐ).hàng;
v : = front(HĐ).cột;
DeQueue(HĐ);
{kiểm tra các cách nhảy của ngựa vào ô tiếp theo. Nếu ô đó nằm trong bàn cờ và chưa xét thì cho vào hàng đợi. Gán chỉ số ô tiếp theo bằng chỉ số ô trước nó cộng thêm 1. Có nghĩa là chỉ số của ô sẽ bằng số lần nhảy từ ô xuất phát đến ô đó}
IF ((u ≤ 6 & v ≥ 1) & Đã_xét(a(u + 2, v - 1)) = 0) THEN
Enqueue (a(u + 2, v - 1), HĐ);
Đã_xét(a(u + 2, v - 1) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 6 & v ≤ 7) & Đã_xét(a(u + 2, v + 1)) = 0) THEN
Enqueue (a(u + 2, v + 1), HĐ);
Đã_xét(a(u + 2, v + 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 7 & v ≤ 6) & Đã_xét(a(u + 1, v + 2)) = 0) THEN
Enqueue (a(u + 1, v + 2), HĐ);
Đã_xét(a(u + 1, v + 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 1 & v ≤ 6) & Đã_xét(a(u - 1, v + 2)) = 0) THEN
Enqueue (a(u - 1, v + 2), HĐ);
Đã_xét(a(u - 1, v + 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 2 & v ≥ 7) & Đã_xét(a(u - 2, v + 1)) = 0) THEN
Enqueue (a(u - 2, v + 1), HĐ);
Đã_xét(a(u - 2, v + 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 2 & v ≥ 1) & Đã_xét(a(u - 2, v - 1)) = 0) THEN
Enqueue (a(u - 2, v - 1), HĐ);
Đã_xét(a(u - 2, v - 1)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≥ 1 & v ≥ 2) & Đã_xét(a(u - 1, v - 2)) = 0) THEN
Enqueue (a(u - 1, v - 2), HĐ);
Đã_xét(a(u - 1, v - 2)) : = Đã_xét(a(u, v)) + 1;
IF ((u ≤ 7 & v ≥ 2) & Đã_xét(a(u + 1, v - 2)) = 0) THEN
Enqueue (a(u + 1, v - 2), HĐ);
Đã_xét(a(u + 1, v - 2)) : = Đã_xét(a(u, v)) + 1;
{Viết lại đường đi của con mã (viết ngược, nếu muốn viết xuôi, có lẽ đổi vai trò cho chúng ngay từ đầu. Vì đường đi ngắn nhất từ (x y)→(i, j) cũng chính là đường đi ngắn nhất từ (i, j)→(x y))}
k : = Đã_xét (a(x, y));
u : = x;
v : = y;
write(a(u, v);
WHILE k ≠1 DO
IF ((u ≤ 6 & v ≥ 1) & Đã_xét(a(u + 2, v - 1)) = k - 1) THEN k : = k - 1; u0 : = u + 2; v0 : = v - 1;
IF ((u ≤ 6 & v ≤ 7) & Đã_xét(a(u + 2, v + 1)) = k - 1) THEN k : = k - 1; u0 : = u + 2; v0 : = v + 1;
IF ((u ≤ 7 & v ≤ 6) & Đã_xét(a(u + 1, v + 2)) = k - 1) THEN k : = k - 1; u0 : = u + 1; v0 : = v + 2;
IF ((u ≥ 1 & v ≤ 6) & Đã_xét(a(u - 1, v + 2)) = k - 1) THEN k : = k - 1; u0 : = u - 1; v0 : = v + 2;
IF ((u ≥ 2 & v ≥ 7) & Đã_xét(a(u - 2, v + 1)) = k - 1) THEN k : = k - 1; u0 : = u - 2; v0 : = v + 1;
IF ((u ≥ 2 & v ≥ 1) & Đã_xét(a(u - 2, v - 1)) = k - 1) THEN k : = k - 1; u0 : = u - 2; v0 : = v - 1;
IF ((u ≥ 1 & v ≥ 2) & Đã_xét(a(u - 1, v - 2)) = k - 1) THEN k : = k - 1; u0 : = u - 1; v0 : = v - 2;
IF ((u ≤ 7 & v ≥ 2) & Đã_xét(a(u + 1, v - 2)) = k - 1) THEN k : = k - 1; u0 : = u + 1; v0 : = v - 2;
u : = u0;
v : = v0;
write(a(u, v));
- May mà viết sẵn ở trong word, chẳng biết bấm chỉnh sửa gì mà toàn bộ dấu + ("cộng") bị mất hết. Mấy bài trung tố, hậu tố tôi đọc cũng bị mất hết dấu cộng. Viết ở Firefox thì mới thêm được bảng, nhưng lại gặp rắc rối này.