Bài toán: Giả sử ta có s đống đĩa, s≥3, mỗi đống chứa n đĩa, được đánh số từ 0 đến s−1, và m=2s cọc, được đánh số từ 0 đến 2s−1. Các đống đĩa là đồng nhất, ngoại trừ màu của chúng. Như vậy, có s đống đĩa đôi một khác màu nhau. Lúc đầu đống đĩa thứ ,i i=0,...,s−1 tương ứng nằm trên các cọc
2 .i
Yêu cầu của bài toán là: Đống đĩa thứ i bắt đầu từ cọc thứ 2i có thể tạm thời sử dụng cọc thứ 2i+1, và phải kết thúc trên cọc thứ (2i+2 .) Ở đây tất cả các số được rút gọn theo mod(2 ),s nghĩa là đống đĩa thứ s−1 ở cọc thứ
2s−2 được chuyển sang cọc 2 ,s chính là cọc 0.
Như vậy cọc thứ 2i vừa đóng vai trò cọc xuất phát của đống đĩa thứ i đồng thời cũng là cọc đến của đống đĩa thứ i−1, và cọc thứ 2i+1chỉ được sử dụng duy nhất cho đống thứ .i Hình 2.8 chỉ ra phiên bản này cho bài toán bốn đống đĩa bốn màu (s=4), mỗi đống chứa bốn đĩa (n=4).
Hình 2.8
Định lí 5 [12] Số bước chuyển tối ưu trong phiên bản 3 là s(2n − +1) 2 .n−1
Thuật toán tối ưu giải bài toán này được mô tả trong [12] như sau.
Các bước thực hiện: Kỹ thuật đánh giá dưới mà ta sử dụng ở hai phiên bản
trên không áp dụng được cho Phiên bản 3, bởi vì có thể phải chuyển liên tiếp các đĩa lớn trong lời giải tối ưu, cũng có thể phải chuyển liên tiếp các đĩa nhỏ nhất. Tuy nhiên, mỗi đống đĩa bị giới hạn chỉ được phép chuyển trong ba cọc, và phải chuyển từ cọc này đến cọc khác. Vì vậy, (2s n −1) là đánh giá dưới. Mặt khác, thuật toán tối ưu cho Phiên bản 2 gợi ý rằng, phiên bản này có thể cần (s+1)(2n −1) lần chuyển.
Ta thấy hai Phiên bản 2 là tương đương Phiên bản 3 trong trường hợp s =2. Tuy nhiên khi n≥3 thì hai bài toán là khác nhau, vì vậy nghiên cứu riêng biệt hai trường hợp s=2 và s≥3 là cần thiết.
Nói riêng, với mọi n≥2, số bước chuyển tối thiểu cho Phiên bản 2 là
( )
3 2n −1 , lớn hơn số bước tối ưu bằng 5.2n−1−2 nhận được từ công thức
(2n 1) 2n 1
s − + − khi s=2 theo Định lí 5. Điều này có nghĩa là thuật toán tối ưu của Phiên bản 3 không thể áp dụng cho Phiên bản 2, bởi vì có thể dẫn tới các bước chuyển đĩa bị cấm.
Thuật toán của phiên bản 3:
Đối với Phiên bản 3, chúng ta có một thuật toán được xây dựng trên một nhóm 4 chương trình con tương đương (coroutines, xem Thuật toán dưới đây).
Ta coi cọc ban đầu của đống i (cọc 2i) là cọc Home của nó, cọc tạm thời của đống i (cọc 2i+1) là cọc Run của nó, và các đích của đống i (cọc 2i+2) là cọc Away của nó. Bốn chữ cái trong tên của mỗi chương trình con được biểu thị theo thứ tự là: chữ cái đầu tiên là cọc mà các đĩa của đống đĩa 0 nằm tại vị trí bắt đầu của chương trình; tiếp theo là cọc mà các đĩa của đống 0 nằm tại vị trí kết thúc trương trình; hai chữ cái còn lại (ở cuối tên của chương trình) ứng với cọc chứa các đĩa của các đống còn lại.
Ví dụ, routine HAHR (n, s) có nghĩa là: có s đống đĩa, và vào lúc khởi đầu chương trình, n đĩa đứng trên đầu của tất cả các đống đĩa nằm ở trên các cọc Home của chúng. Vào cuối của chương trình các đĩa trên cùng của đống đĩa 0 trên cọc Away của nó, trong khi đó các đĩa trên cùng của tất cả các đống còn lại sẽ ở trên các cọc Run của chúng.
Cũng như trước đây, ta giả thiết rằng, thủ tục không thực hiện nếu n là không dương, và tất cả các tham số i của đĩa được rút gọn theo modulo 4.
Thuật toán:
procedure HAHR (n, s)
HRHA(n-1, s); for i from 1 to s-1 do Move(n, i, (2*i), (2*i+1));
Hanoi(n-1, 1, i, (2*i+2), (2*i), (2*i+1)); Move(n, 0, 0, 2);
HAHR(n-1, s); Move(n, 0, 0, 1);
Hanoi(n-1, 1, 0, 2, 0, 1); for i from s-1 down to 1 do Move(n, i, (2*i), (2*i+2);
Hanoi(n-1, 1, i, (2*i+1), (2*i), (2*i+2)); procedure HARA(n, s)
Hanoi(n-1, 1, 0, 0, 2, 1); Move(n, 0, 0, 2);
for i from 1 to s-1 do
Hanoi(n-1, 1, i, (2*i+1), (2*i+2), (2*i)); Move(n, i, (2*i+1), (2*i+2));
procedure RAHA(n, s) for i from s-1 down to 1 do
Hanoi(n-1, 1, i, (2*i), (2*i+2), (2*i+1))); Move(n, i, (2*i), (2*i+2));
Hanoi(n-1, 1, 0, 1, 2, 0); Move(n, 0, 1, 2);
HARA(n-1, s);
Tất cả các quy trình này tạo ra cùng một số lần chuyển. Có thể gọi một quy trình từ những quy trình này, cộng với s lần chuyển một đĩa và s lần gọi quy trình Hanoi theo một thứ tự nào đó.
Kí hiệu ( )H n là số lần chuyển đĩa trong một quy trình. Khi ấy
1 1
( ) ( 1) (2n 1) ( 1) .2 .n
H n =H n− +s − − + =s H n− +s −
Với (0) 0H = . Chứng minh theo quy nạp ta có ( ) (2n 1).
Quy trình này rõ ràng là tối ưu, vì nó thực hiện s lần qui trình Tháp Hà Nội cổ điển một cách riêng biệt.
Một lời giải cho Phiên bản 3 được đưa ra bởi quy trình HAHA dưới đây. Với các giả định thông thường về n và các thông số đống đĩa,
procedure HAHA (n, s)
HAHR(n-1, s); Move(n, 0, 0, 1);
for i from s-1 down to 2 do Move(n, i, (2*i), (2*i+2)); Hanoi(n-1, 1, 0, 2, 1, 0); Move(n, 1, 2, 4);
Move(n, 0, 1, 2); HARA(n-1, s);
Qui trình này trước tiên gọi hai H-thủ tục, gọi một thủ tục Hanoi, và s+1 lần chuyển một đĩa. Cuối cùng ta được tổng cộng
( ) ( ) 1
3 , 2n 1 2n
M n s =s − + − lần chuyển.
Để chỉ ra đây là số lần chuyển tối ưu, ta nhận thấy không phải tất cả các s đĩa kích thước n có thể chuyển trực tiếp từ cọc Home đến các cọc Away của nó. Ít nhất một đĩa như vậy (trên đống 0 trong mã (code) của chúng ta) phải chuyển từ cọc Home đến cọc Run của nó, và sau đó từ cọc Run đến cọc Away. Còn
1
n− đĩa trên đỉnh của đống này đầu tiên phải chuyển ít nhất từ cọc Home đến cọc Away của nó, trước lần chuyển đầu tiên của đĩa lớn nhất, sau đó lại trở lại cọc Home của nó giữa các lần chuyển của đĩa lớn nhất, và trở lại cọc Away của nó khi lần chuyển cuối cùng của đĩa lớn nhất đã được thực hiện. Vì vậy, đống này phải thực hiện ít nhất 3(2n−1− + =1) 2 (2n − +1) 2n−1 lần chuyển.
Còn lại s−1 đống khác phải thực hiện ít nhất 2n −1 lần chuyển, được tổng là ( )
3 , .
M n s
Sử dụng các chương trình HAHR, HARA, Thủ tục Turtle2 dưới đây cho một cách khác để tạo ra qui trình tối ưu cho Phiên bản 2.
procedure Turtle2(n) HAHR(n-1, 2); Move(n, 0, 0, 1); Hanoi(n-1, 1, 0, 2, 0, 1); Move(n, 1, 2, 0); Hanoi(n-1, 1, 0, 1, 2, 0); Move(n, 0, 1, 2); HARA(n-1, 2);