Tower of Hanoi được phát minh bởi nhà toán học người Pháp Édouard Lucas năm 1883 và ông này không có gốc Việt.
Bài toán phát biểu như sau:
- Cho 3 cái cột, cần chuyển các đĩa từ cột 1 sang cột 3, thông qua cột 2
- Mỗi lần chỉ được chuyển 1 đĩa, đĩa bên dưới phải to hơn đĩa bên trên.
Bài giải
Hình ảnh minh họa sinh động bài giải:
Phân tích cách viết function đệ quy:
Đặt 3 cột là source [nguồn], dest [đích], tmp [trung gian], function tên move, ban đầu có thể nghĩ function trông như sau:
Khi viết recursive function, thường sử dụng các argument để lưu trạng thái [state] function. Bài toán này có 1 trạng thái là số lượng đĩa còn lại cần chuyển, ban đầu có giá trị là n, khi kết thúc là 0. Sau mỗi bước chuyển, trạng thái của bài toán được lưu giữ trong số đĩa còn lại và nội dung của mỗi cột. Vậy function sẽ trở thành
move[n, source, dest, tmp]
Có thể cho rằng chỉ cần 3 cột cũng đủ biểu diễn trạng thái của chương trình, không cần tới n
, và dùng len[source]
để tính số đĩa còn lại, nhưng khi giải, các cột lần lượt thay đổi vai trò của nhau khiến không thể biết cột nào là cột source
ban đầu.
Tháp Hà Nội là một câu đố toán học bao gồm ba thanh và nhiều đĩa được đặt chồng lên nhau. Nó còn được gọi là Tháp Brahma hay tháp Lucas, như nhà toán học người Pháp Edouard Lucas đã giới thiệu vào năm 1883. Câu đố này dựa trên truyền thuyết về việc di chuyển các đĩa vàng giữa ba thanh.
Câu đố này có ba thanh và một số lượng đĩa xếp chồng lên nhau. Những thanh này được thiết kế như những tháp tuần hoàn. Vì vậy, các đĩa có đường kính lớn hơn được xếp ở phía dưới và các đĩa nhỏ hơn được xếp ở trên.
Ban đầu, chúng ta được cấp ba cái chốt hoặc que. Và một trong số chúng [A, được hiển thị trong ví dụ] có tất cả các đĩa được xếp chồng lên nhau. Chúng tôi mong muốn di chuyển toàn bộ chồng đĩa từ thanh này [A] sang thanh khác [C] bằng cách tuân theo một số quy tắc cụ thể.
Đây là thiết lập ban đầu của câu đố-
Và đây là mục tiêu cuối cùng-
Quy định của Tháp Hà Nội
Dưới đây là một số quy tắc cần thiết cho Tháp Hà Nội:
- Trạng thái ban đầu của câu đố này là tất cả các đĩa sẽ được xếp thành một thanh.
- Trạng thái cuối cùng là tất cả các đĩa từ thanh một sẽ được xếp chồng lên thanh hai hoặc thanh ba.
- Chúng ta có thể di chuyển một đĩa từ thanh này sang thanh khác vào bất kỳ thời điểm nào.
- Chúng ta chỉ có thể di chuyển đĩa trên cùng khỏi thanh.
- Không thể đặt một đĩa lên trên một đĩa khác nhỏ hơn.
Truyền thuyết ban đầu là về việc di chuyển 64 chiếc đĩa. Các linh mục có thể di chuyển từng đĩa một theo quy định. Theo truyền thuyết, có một lời tiên tri rằng thế giới sẽ kết thúc nếu họ có thể hoàn thành hành động. Trong thời gian complexTrong phần này, chúng tôi sẽ chỉ ra rằng một bộ n đĩa của Tháp Hà Nội sẽ tốn 2^n – 1 lần di chuyển.
Vì vậy, nếu các linh mục có thể cần 1 giây để di chuyển các đĩa, tổng thời gian họ cần để giải câu đố sẽ là 2^64 – 1 giây hoặc 584,942,417,356 năm, 26 ngày, 7 hours, và 15 giây.
Thuật toán Tháp Hà Nội
Một cách tổng quát để giải Tháp Hà Nội là sử dụng thuật toán đệ quy. Đầu tiên, chúng ta cần quyết định hai thanh hoặc chốt làm nguồn và đích, còn chốt dự phòng sẽ là phụ trợ hoặc trợ giúp.
Dưới đây là các bước giải câu đố Tháp Hà Nội:
- Di chuyển n-1 đĩa trên cùng từ chốt nguồn sang chốt trợ giúp.
- Sau đó, di chuyển đĩa thứ n từ chốt nguồn sang chốt đích.
- Cuối cùng, di chuyển n-1 đĩa còn lại từ chốt trợ giúp sang chốt đích.
Chú thích: Nếu chúng ta có một đĩa đơn, chúng ta có thể di chuyển trực tiếp nó từ nguồn tới đích.
Cách giải câu đố Tháp Hà Nội
Hãy minh họa thuật toán cho ba đĩa và coi chốt A là nguồn, chốt B là trợ giúp và chốt C là đích
Bước 1] Ban đầu, tất cả các đĩa sẽ được xếp chồng lên cọc A.
Ở giai đoạn này:
Nguồn = Chốt A Đích = Chốt C Người trợ giúp = Chốt B
Bây giờ, chúng ta cần di chuyển n-1 đĩa hàng đầu từ nguồn sang trợ giúp.
Lưu ý: Mặc dù chúng tôi chỉ có thể di chuyển một đĩa mỗi lần, nhưng nó sẽ chuyển vấn đề của chúng tôi từ vấn đề 3 đĩa sang vấn đề 2 đĩa, đó là một cuộc gọi đệ quy.
Bước 2] Khi chúng ta gọi một cuộc gọi đệ quy từ chốt A và đích đến là chốt B, chúng ta sẽ sử dụng chốt C làm trợ giúp.
Lưu ý rằng chúng ta lại đang ở giai đoạn một của bài toán tháp Hà Nội cho hai đĩa.
Bây giờ chúng ta cần di chuyển n-1 hoặc một đĩa từ nguồn sang trợ giúp, di chuyển đĩa nhỏ nhất từ chốt A sang chốt C.
Ở giai đoạn này:
Nguồn = chốt A Đích = chốt B Người trợ giúp = chốt C
Bước 3] Sau đó, theo thuật toán của chúng tôi, nhu cầu đĩa thứ n hoặc thứ 2 sẽ được chuyển vào đích hoặc chốt B.
Ở giai đoạn này:
Nguồn = chốt A Đích = chốt B Người trợ giúp = chốt C
Bước 4] Bây giờ, chúng tôi sẽ di chuyển n-1 đĩa hoặc đĩa một từ trợ giúp hoặc chốt C đến đích hoặc chốt B theo giai đoạn thứ ba của thuật toán của chúng tôi.
Ở giai đoạn này:
Nguồn = chốt A Đích = chốt B Người trợ giúp = chốt C
Bước 5] Sau khi hoàn thành lệnh gọi đệ quy, chúng ta sẽ quay lại cài đặt trước đó khi ở giai đoạn đầu tiên của thuật toán.
Bước 6] Bây giờ, trong giai đoạn thứ hai, chúng ta sẽ di chuyển nguồn đến đích, tức là di chuyển đĩa 3 sang chốt C từ chốt A.
Ở giai đoạn này:
Nguồn = chốt A Đích = chốt C Người trợ giúp = chốt B
Bước 7] Bây giờ chúng ta có thể thấy điều đó
d là di chuyển các đĩa còn lại từ trợ giúp [peg B] đến đích [peg C]. Chúng tôi sẽ sử dụng nguồn ban đầu hoặc chốt A làm trợ giúp trong trường hợp này.
Bước 8] Vì chúng ta không thể di chuyển hai đĩa cùng một lúcneoThông thường, chúng ta sẽ gọi lệnh gọi đệ quy cho đĩa 1. Theo bước cuối cùng và thuật toán, đích đến ở bước này là chốt A.
Ở giai đoạn này:
Nguồn = chốt B Đích = chốt A Người trợ giúp = chốt C
Bước 9] Cuộc gọi đệ quy của chúng tôi đã hoàn tất. Sau đó, chúng tôi di chuyển đĩa 2 từ nguồn đến đích.
Ở giai đoạn này:
Nguồn = chốt B Đích = chốt C Người trợ giúp = chốt A
Bước 10] Sau đó, chúng tôi di chuyển n-1 hoặc đĩa 1 còn lại từ trợ giúp đến đích.
Ở giai đoạn này:
Nguồn = chốt A Đích = chốt C Người trợ giúp = chốt B
Mã giả Tháp Hà Nội
START Procedure Tower_Of_Hanoi[disk, source, dest, helper]
IF disk == 1, THEN
move disk from source to dest
ELSE
Tower_Of_Hanoi [disk - 1, source, helper, dest]
move disk from source to dest
Tower_Of_Hanoi [disk - 1, helper, dest, source]
END IF
END ProcedureMã chương trình trong C++
include
using namespace std; void tower_of_hanoi[int num, string source, string dest, string helper] { if [num == 1] {
cout