24.8.14

Trò chơi Tháp Hà Nội

Trò chơi Tháp Hà Nội
Tháp Hà Nội hay có tên tiếng Anh là "Tower of Hanoi" ( Còn có những tên gọi phổ biến khác như Tower of Brahma, Lucas' Tower) là một game toán học độc đáo. Để hiểu thêm về trò này các bạn có thểm tìm đọc thêm ở trên Wikipedia - Tháp Hà Nội.

Tháp Hà Nội là tên một bài toán rất nổi tiếng trong Chương trình khoa học tính toán (Computing Science) dành cho sinh viên những năm đầu tại các trường đại học ở nhiều nơi trên thế giới. Sau đây là lược trích nội dung bài toán từ cuốn sách giáo khoa dành cho sinh viên ngành thuật toán và lập trình - "Giải toán nâng cao và cấu trúc dữ liệu" (Intermediate problem solving and data structures) do Paul Henman và Robert Veroff, hai giáo sư Đại học New Mexico, cùng biên soạn với Frank Carrano, giáo sư Đại học Rhode Island (Mỹ):

"Tương truyền rằng ngày xửa ngày xưa, lâu lắm rồi, ở một vùng xa xôi viễn đông, thành phố Hà Nội của Việt Nam, vị quân sư của Hoàng đế vừa qua đời, Hoàng đế cần một vị quân sư mới thay thế. Bản thân Hoàng đế cũng là một nhà thông thái, nên ngài đặt ra một bài toán đố, tuyên bố ai giải được sẽ được phong làm quân sư. Bài toán của Hoàng đế là: cho n cái đĩa (ngài không nói chính xác là bao nhiêu) và ba cái trục: A là trục nguồn, B là trục đích, và C là trục trung chuyển. Những cái đĩa có kích cỡ khác nhau và có lỗ ở giữa để có thể lồng vào trục, theo quy định "nhỏ trên lớn dưới". Đầu tiên, những cái đĩa này được xếp tại trục A. Vậy làm thế nào để chuyển toàn bộ các đĩa sang trục B, với điều kiện chuyển từng cái một và luôn phải đảm bảo quy định "nhỏ trên lớn dưới", biết rằng trục C được phép sử dụng làm trục trung chuyển?

Vì địa vị quân sư được coi là vinh hiển nên có rất nhiều người dự thi. Từ vị học giả đến bác nông phu, họ đua nhau trình lên Hoàng đế lời giải của mình. Nhiều lời giải dài tới hàng nghìn bước, và nhiều lời giải có chữ "chuyển sang bước tiếp theo" (go to). Nhưng hoàng đế thấy mệt mỏi vì những lời giải đó, nên cuối cùng hạ chiếu: "Ta không hiểu những lời giải này. Phải có một cách giải nào khác dễ hiểu và nhanh chóng hơn". May mắn thay, cuối cùng đã có một cách giải như thế.

Thật vậy, ngay sau khi chiếu vua ban ra, một vị cao tăng trông bề ngoài giống như một kỳ nhân hạ sơn tới xin yết kiến hoàng đế. Vị cao tăng nói: "Thưa Bệ hạ, bài toán đố đó dễ quá, hầu như nó tự giải cho nó". Quan trùm cấm vệ đứng hầu ngay bên cạnh vua quắc mắt nhìn gã kỳ nhân, muốn quẳng gã ra ngoài, nhưng Hoàng đế vẫn kiên nhẫn tiếp tục lắng nghe. "Nếu chỉ có 1 đĩa, thì...; nếu có nhiều hơn 1 đĩa (n>1), thì...", cứ thế vị cao tăng bình tĩnh giảng giải. Im lặng được một lát, cuối cùng Hoàng đế sốt ruột gắt: "Được, thế cao tăng có nói rõ cho ta lời giải hay không cơ chứ?". Thay vì giải thích tiếp, gã kỳ nhân mỉm cười thâm thúy rồi biến mất, bởi vì hoàng đế tuy giỏi giang nhưng rõ ràng là chưa hiểu ý nghĩa của phép truy hồi (recursion). Nhưng các bạn sinh viên ngày nay thì có thể thấy cách giải của vị cao tăng là hoàn toàn đúng."

Tháp Hà Nội là một bài toán thường được dùng để dạy về lập trình cơ bản. Một phiên bản bằng hình của bài toán này được lập trình trong chương trình soạn thảo emacs, có thể truy cập được bằng cách gõ M-x hanoi. Ngoài ra cũng có một thuật giải mẫu viết bằng ngôn ngữ Prolog.

Bài toán Tháp Hà Nội thường được dùng trong nghiên cứu tâm lý về cách giải quyết vấn đề. Cũng có những biến thể khác của bài toán này gọi là Tháp Luân Đôn dùng trong chuẩn đoán và điều trị thần kinh tâm lý đối với các chức năng thực hành.

Về luật chơi:

Dạng thường gặp nhất của trò chơi này gồm một bộ các đĩa kích thước khác nhau, có lỗ ở giữa, nằm xuyên trên ba cái cọc. Bài toán đố bắt đầu bằng cách sắp xếp các đĩa theo trật tự kích thước vào một cọc sao cho đĩa nhỏ nhất nằm trên cùng, tức là tạo ra một dạng hình nón. Yêu cầu của trò chơi là di chuyển toàn bộ số đĩa sang một cọc khác, tuân theo các quy tắc sau:

Chỉ có 3 cột để di chuyển.

Một lần chỉ được di chuyển một đĩa (không được di chuyển đĩa nằm giữa).

Một đĩa chỉ có thể được đặt lên một đĩa lớn hơn (không nhất thiết hai đĩa này phải có kích thước liền kề, tức là đĩa nhỏ nhất có thể nằm trên đĩa lớn nhất).

Luật chơi phía trên là luật chung. Dưới đây cách chơi cụ thể hơn với flash game ở bài đăng này:

Chuyển hết đĩa từ cột A sang cột C. Số lần di chuyển càng ít, thời gian giải xong càng nhanh bạn càng được nhiều điểm.

Bấm Start đầu trò chơi. Sau đó sẽ xuất hiện mũi tên lên và xuống, bạn bấm vào để tăng hoặc giảm số đĩa ở mỗi cột (Ở đây tối thiểu là 1 đĩa, tối đa là 10 đĩa) càng nhiều đĩa thì càng khó. (Bạn giải được ở 8 đĩa thì được coi là khá, từ 9 đĩa trở lên thì là giỏi rồi đó!)

Bấm restart (Ở góc trái) nếu muốn làm lại từ đầu.

Bạn có thể share kết quả về wall trên facebook hoặc các mạng xã hội phổ biến khác để "khoe" với bạn bè!

Đây là bài toán nế có cách giải. Cách giải theo công thức được lấy từ wiki và để ngay bên dưới, bạn có thể xem để nghiên cứu thêm.

Cách giải thực tế

Nhiều cách giải đã được phát triển trong bài toán tháp Hà Nội. Ở đây giới thiệu một cách chơi thực tế.

Lần lượt di chuyển đĩa 1 và một trong những đĩa lớn hơn. Nếu có hai đĩa lớn hơn thì phải chuyển đĩa nhỏ lên đĩa lớn. Khi chuyển một đĩa số lẻ, luôn chuyển nó một cọc theo chiều kim đồng hồ; khi chuyển một đĩa số chẵn, luôn chuyển nó một cọc ngược chiều kim đồng hồ.

Một cách dễ hơn để nhớ cách giải là chú ý đĩa nhỏ nhất sẽ được chuyển mỗi lần di chuyển thứ hai, và luôn được chuyển theo cùng chiều. Trong các lần chuyển đĩa nhỏ nhất, chỉ có một lần chuyển hợp lệ mà không phải chuyển đĩa nhỏ nhất thêm một lần nữa.

Lời giải cho 3 đĩa. 

Lời giải cho 4 đĩa.


Cách giải khác

Mục đích của bài toán là thực hiện được yêu cầu của trò chơi. Dạng bài toán thông dụng nhất là: "Người chơi được cho ba cái cọc và một số đĩa có kích thước khác nhau có thể cho vào các cọc này. Ban đầu sắp xếp các đĩa theo trật tự kích thước vào một cọc sao cho đĩa nhỏ nhất nằm trên cùng, tức là tạo ra một dạng hình nón. Người chơi phải di chuyển toàn bộ số đĩa sang một cọc khác, tuân theo các quy tắc sau:

Một lần chỉ được di chuyển một đĩa

Một đĩa chỉ có thể được đặt lên một đĩa lớn hơn (không nhất thiết hai đĩa này phải có kích thước liền kề, tức là đĩa nhỏ nhất có thể nằm trên đĩa lớn nhất)".

Bài toán này có lời giải chính xác. Tuy nhiên các mở rộng cho trường hợp có nhiều hơn ba cọc cho đến nay vẫn chưa được giải cặn kẽ.

Đa số các trò chơi dạng này có 8 đĩa. Đối với người mới chơi thì có vẻ khó nhưng thật ra thuật giải của nó hết sức đơn giản:

Thuật giải đệ quy

Đặt tên các cọc là A, B, C -- những tên này có thể chuyển ở các bước khác nhau (ở đây: A = Cọc Nguồn, B = Cọc Đích, C = Cọc Trung Gian)

Gọi n là tổng số đĩa

Đánh số đĩa từ 1 (nhỏ nhất, trên cùng) đến n (lớn nhất, dưới cùng)

Để chuyển n đĩa từ cọc A sang cọc B thì cần:

Chuyển n-1 đĩa từ A sang C. Chỉ còn lại đĩa #n trên cọc A

Chuyển đĩa #n từ A sang B

Chuyển n-1 đĩa từ C sang B cho chúng nằm trên đĩa #n

Phương pháp trên được gọi là thuật giải đệ quy: để tiến hành bước 1 và 3, áp dụng lại thuật giải cho n-1. Toàn bộ quá trình là một số hữu hạn các bước, vì đến một lúc nào đó thuật giải sẽ áp dụng cho n = 1. Bước này chỉ đơn giản là chuyển một đĩa duy nhất từ cọc A sang cọc C.

Ngôn ngữ Pascal biểu diễn giải thuật trên là:

VAR n: Integer;
Procedure chuyen(sodia: Integer; CotNguon: Char; CotDich: Char; CotTG: Char);
   Begin
        If sodia>0 then begin
           chuyen(sodia-1, CotNguon, CotTG, CotDich);
           Writeln(CotNguon,'->',CotDich); { Dia lon nhat hien tai }
           chuyen(sodia-1, CotTG, CotDich, CotNguon)
        End;
   End;
BEGIN
     Write('Hay nhap so dia: '); Readln(n);
     chuyen(n,'A','C','B');//Thực hiện chuyển từ cột A sang cột C với cột B làm trung gian
     Readln;
END.


Ngôn ngữ C viết trên Dev C++

#include <cstdlib>
#include <iostream>
#include <conio.h>
 
using namespace std;
void chuyen(int sodia, char CotNguon, char CotDich, char CotTG)
{
        if (sodia>0)
        {
           chuyen(sodia-1, CotNguon, CotTG, CotDich);
           cout<<CotNguon<<"->"<<CotDich<<"\n";
           chuyen(sodia-1, CotTG, CotDich, CotNguon);
        }
}
int main()
{    char CotNguon,CotDich,CotTG;
    int n;
     cout<<"Hay nhap so dia: ";
     cin>>n;
     chuyen(n,'A','C','B');
     getch();
}

Giải thuật bằng biểu diễn nhị phân

Các vị trí đĩa có thể xác định được trực tiếp từ biểu diễn nhị phân của số thứ tự di chuyển (cơ số 2 với một chữ số cho mỗi đĩa) trong đó các dãy 1 và các dãy 0 tượng trưng cho các dãy các đĩa liền nhau trên cùng cọc, và mỗi khi chữ số có thay đổi thì đĩa kế tiếp sẽ dời sang trái hay phải một cọc (hay chuyển sang cọc ngoài cùng phía đối diện). Chữ số ở đầu đại diện cho đĩa lớn nhất và nếu là chữ số 0 thì có nghĩa là đĩa lớn nhất không dời khỏi cọc xuất phát và ngược lại. Đặt các chữ số 1 và 0 luân phiên bên dưới các chữ số của một bước chuyển cho phép biết được di chuyển theo một chiều khi nó hợp với chữ số của bước chuyển tại nơi chữ số thay đổi và theo chiều kia khi nó không hợp. Do đó bước chuyển 00000000... có nghĩa là đặt 8 đĩa lớn nhất lên cọc ban đầu, bước chuyển 11111111... có nghĩa là đặt chúng lên cọc cuối cùng, và bước chuyển 11011000... có hai đĩa lớn nhất trên cọc đích, đĩa tiếp theo trên cọc xuất phát, hai đĩa tiếp theo ở cọc trung gian, và ba đĩa tiếp theo nữa trên cọc xuất phát, bất kể có thêm bao nhiêu chữ số đại diện các đĩa nhỏ hơn. Ta có thể dễ dàng tính được các vị trí của các đĩa trong một bộ tám mươi đĩa sau một số các bước tiến, nếu giới hạn đủ lớn để chứa nó. Việc dùng phương pháp đệ quy cho trường hợp tám mươi đĩa như thế này có thể không thực tế.
  1. Trả lời
    1. Mới giải đến cái đĩa thứ 7, chưa biết khi nào xong (-, -- )

      Xóa
  2. thanks :D greting from indonesia :D

    Trả lờiXóa
  3. tìm đc quy luật r thì bao nhiêu thanh cũng thế chỉ có khác là thỉnh thoảng hơi bị rối thôi :D

    Trả lờiXóa
  4. Khó phết đấy! 1396s và 912 lần bấm cho 8 cái đĩa |o|

    Trả lờiXóa

Mong sẽ nhận được sự giúp đỡ của các bạn để logictrochoi ngày một hoàn thiện.

» Càng nhiều bình luận càng nhiều bài viết mới.

» Nếu phát hiện có vấn đề gì về câu đố hoặc blog xin hãy góp ý.

» Khuyến khích viết Tiếng Việt có dấu!

» Tạo chữ <b>Đậm</b> và <i>Ngiêng</i>

Start typing and press Enter to search