{--- Kiem tra tinh chat ke giua 2 coc a va b Kiem tra tinh chat ke giua 2 coc a va b ---} function Ke(n,a,b: byte): Boolean;
begin case s[n] of 'x': ke := (b = (a mod 3)+1); 'n': ke := (a = (b mod 3)+1); 't': Ke := (abs(a-b) = 1); 'h': Ke := True; end {case}; end; (*--- Ha Noi sac mau
x: xanh - xuoi chieu kim dong ho n: nau - nguoc chieu kim dong ho n: nau - nguoc chieu kim dong ho t: trang - chuyen thang
h: hong - chuyen tu do
---*) procedure Hnm(n: byte; a,b: byte); tự viết procedure Hnm(n: byte; a,b: byte); tự viết {---
To chuc goi thu tuc Hnm
---} procedure runHnm(Thap:string); procedure runHnm(Thap:string); begin s := Thap; d := 0; assign(f,'hnm.out'); rewrite(f); writeln('---');
Hnm(length(s),1,2); writeln(f,'Total: ',d,' step(s)'); close(f); readln; end; BEGIN runHnm('txhxn'); END. // C# using System; namespace SangTao1 { /*--- * Thap Ha Noi * ---*/ class ThapHaNoi { static int d = 0;
static char[] s = new char[64]; static void Main()
{
Console.WriteLine("\n Ha Noi Sac Mau"); RunHaNoiSacMau("xnxht", 1, 2);
Console.WriteLine("\n Total: " +
d + " steps"); Console.ReadLine();
} // Main
static bool Ke(char KieuThap, int a, int b) {
switch (KieuThap) {
case 'x': return (b == (a % 3) + 1); case 'n': return (a == (b % 3) + 1); case 't': return (Math.Abs(a - b) == 1); }
return true; }
/*--- Ha Noi sac mau Ha Noi sac mau
x: xanh - xuoi chieu kim dong ho n: nau - nguoc chieu kim dong ho n: nau - nguoc chieu kim dong ho t: trang - chuyen thang
h: hong - chuyen tu do
---*/ void HaNoiSacMau(int n, int a, int b) void HaNoiSacMau(int n, int a, int b)
{
if (n == 0) return; if (Ke(s[n], a, b)) {
Console.WriteLine((++d)+ ". ("+s[n]+") "+a+" -> "+b); HaNoiSacMau(n - 1, 6 - a - b, b); } else { HaNoiSacMau(n - 1, a, b); Console.WriteLine((++d)+ ". ("+s[n]+") " +a+" -> "+(6-a-b)); HaNoiSacMau(n - 1, b, a); Console.WriteLine((++d)+ ". ("+s[n]+")" +(6-a-b) +" -> "+b); HaNoiSacMau(n - 1, a, b); } }
static void RunHaNoiSacMau(string w, int a, int b) { d = 0; w.CopyTo(0, s, 1, w.Length); HaNoiSacMau(w.Length, a, b); } } // ThapHaNoi } // SangTao1 Hƣớng dẫn kiểm thử
Ta sẽ dựng kĩ thuật đối sỏnh để kiểm thử cỏc trường hợp.
Ta chọn và cố định cỏc giỏ trị n, a và b. Chẳng hạn, n = 4, a = 1, b = 2. Khi đú ta cú:
RunHn(n) và RunHnm('hhhh') cho cựng kết quả.
RunHnx(n) và RunHnm('xxxx') cho cựng kết quả.
RunHnn(n) và RunHnm('nnnn') cho cựng kết quả.
RunHnt(n) và RunHnm('tttt') cho cựng kết quả.
Nếu ghi cỏc kết quả này vào cỏc tệp tương ứng, sau đú gọi thủ tục đối sỏnh từng cặp hai tệp tương ứng thỡ cú thể kiểm định được một số trường hợp.
Để xõy dựng cỏc tỡnh huống kiểm thử khỏc nhau cũn lại bạn để ý đến cỏc tớnh chất thuận nghịch của cỏc thủ tục khỏc nhau. Thớ dụ, như đó phõn tớch ở phần trờn, cỏc lời gọi Hnx(3,1,2) và Hnn(3,3,1) phỏt sinh cựng một số lần chuyển.
Bạn hóy thử phỏt hiện thờm sự tương đồng giữa cỏc lời gọi Hnm với cỏc tham trị khỏc nhau.
Đọc thờm
Lƣơc sử
Một số bài toỏn về thỏp Hà Nội đó được đưa vào cỏc kỡ thi Olympic Tin học tại một số quốc gia. Chỳng ta thử tỡm hiểu cội nguồn của cỏc bài toỏn thuộc loại này.
Năm 1883, trờn một tờ bỏo ở Paris cú đăng bài mụ tả một trũ chơi toỏn học của giỏo sư Claus với tờn là Thỏp Hà Nội. Nội dung trũ chơi được mọi người say mờ làm thử chớnh là bài toỏn Thỏp Hà Nội cổ.
Thời đú ở thủ đụ Paris dõn chỳng đổ xụ nhau mua đồ chơi này và suốt ngày ngồi chuyển thỏp. Trong lịch sử về cỏc trũ chơi thụng minh đó từng cú những cơn sốt như vậy. Tớnh trung bỡnh mỗi thế kỉ cú một vài cơn sốt trũ chơi. Thế kỉ thứ XX cú cơn sốt Rubic, thế kỉ XIX là cỏc trũ chơi 15 và thỏp Hà Nội. Bài toỏn này nổi tiếng đến mức trở thành kinh điển trong cỏc giỏo trỡnh về thuật giải đệ quy và được trỡnh bày trong cỏc thụng bỏo chớnh thức của cỏc phiờn bản chuẩn của cỏc ngữ trỡnh như ALGOL-60, ALGOL-68, Pascal, Delphy, C, C++, Ada,... khi muốn nhấn mạnh về khả năng đệ quy của cỏc ngụn ngữ đú.
Theo nhà nghiờn cứu Henri De Parville cụng bố vào năm 1884 thỡ tỏc giả của trũ chơi thỏp Hà Nội cú tờn thật là nhà toỏn học Eduard Lucas, người cú nhiều đúng gúp trong lĩnh vực số luận. Mỗi khi viết về đề tài giải trớ thỡ ụng đổi tờn là Claus. Bạn cú để ý rằng Claus là một hoỏn vị cỏc chữ cỏi của từ Lucas.
De Parville cũn kể rằng bài toỏn thỏp Hà Nội bắt nguồn từ một tớch truyền kỡ ở Ấn Độ. Một nhúm cao tăng Ấn Độ giỏo được giao trọng trỏch chuyển dần 64 đĩa vàng giữa ba cọc kim cương theo cỏc điều kiện đó núi ở bài toỏn Thỏp Hà Nội cổ. Khi nào hoàn tất cụng việc, tức là khi chuyển xong toà thỏp vàng 64 tầng từ vị trớ ban đầu sang vị trớ kết thỳc thỡ cũng là thời điểm tận thế. Sự việc này cú xảy ra hay khụng ta sẽ xột ở bài tập 8.10.
Lời giải được cụng bố đầu tiờn cho bài toỏn thỏp Hà Nội là của Allardice và Frase, năm 1884.
Năm 1994 David G. Poole ở Đại học Trent, Canada đó viết một bài khảo cứu cho tờ Mathematics Magazine số thỏng 12 nhan đề "Về cỏc thỏp và cỏc tam giỏc của giỏo sư Claus" cựng với một phụ đề "Pascal biết Hà Nội". Poole đó liệt kờ 65 cụng trỡnh khảo cứu bài toỏn thỏp Hà Nội đăng trờn cỏc tạp chớ toỏn-tin trong khoảng mười năm. Tỏc giả cũng chỉ ra sự liờn quan giữa cỏc cụng thức tớnh số lần chuyển cỏc tầng thỏp và một phương phỏp quen biết dựng để tớnh cỏc hệ số của dạng khai triển nhị thức Newton (a + b)n. Phương phỏp này được gọi là Tam giỏc Pascal, mang tờn nhà toỏn học kiờm vật lớ học Phỏp Blaise Pascal (1623-1662), người đó chế tạo chiếc mỏy tớnh quay tay đầu tiờn trờn thế giới.
Một số nhà nghiờn cứu trong và ngoài nước cú bàn luận về địa danh Hà Nội. Theo tụi vấn đề này vẫn cũn ngỏ. Hầu hết cỏc bài viết xoay quanh đề tài chuyển thỏp núi trờn đều dựng thuật ngữ bài toỏn thỏp Hà Nội. Khi giới thiệu về bài toỏn Hà Nội nhiều thỏp Dudeney đặt tờn là bài toỏn đố của Reve (The Reve's Puzzle). Tuy nhiờn, nhiều nhà nghiờn cứu cho rằng tốt hơn cả là nờn đặt tờn và phõn loại theo tờn nguyờn thuỷ của bài toỏn, nghĩa là Thỏp Hà Nội.
Ngoài cỏc dạng Thỏp Hà Nội đó liệt kờ ở phần trờn một số tỏc giả cũn đề xuất những dạng khỏ kỡ lạ, chẳng hạn như bài toỏn sau đõy.
Hà Nội nhiều thỏp
Trong trũ chơi này người ta làm thờm những cọc, chẳng hạn thay vỡ ba ta dựng bốn cọc và cũng cú thể bố trớ thỏp tại nhiều cọc. í kiến này do H.E. Dudeney, một tỏc giả hàng đầu về toỏn học giải trớ người Anh đưa ra vào năm 1908. Đó cú nhiều bài đăng lời giải cho bài toỏn này, cú những bài mới xuất hiện gần đõy vào những năm 1988 và 1989. Dự vậy chưa ai chứng minh được rừ ràng số lần chuyển của bài giải là tối thiểu như đó làm với cỏc dạng thỏp Hà Nội khỏc.
Bài tập
Bạn hóy thử lập cụng thức tớnh số lần chuyển cỏc tầng tối thiểu cho cỏc bài toỏn sau:
Thỏp Hà Nội, Thỏp Hà Nội Xuụi, Thỏp Hà Nội Ngược và
Thỏp Hà Nội Thẳng.
Lời cảm ơn Cỏc tư liệu trờn và một số tư liệu khỏc trong bài được trớch dẫn từ cỏc bài viết của giỏo sư viện sĩ Nguyễn Xuõn Vinh, Khoa Kỹ thuật khụng gian, Đại học Michigan, cộng tỏc viờn NASA, Hoa Kỳ. Tỏc giả xin chõn thành cỏm ơn giỏo sư đó cho phộp trớch dẫn và chỉ giỏo về cỏc phương phỏp truyền thụ tri thức khoa học cho giới trẻ.
NXH 8/4/2008