Bí mật của một thuật toán
12/10/2006

Chúng ta sẽ làm quen với một bài toán, hay nói đúng hơn là một thuật toán rất đơn giản. Thuật toán này đơn giản đến nỗi chắc các bạn sau khi xem qua sẽ đều “tặc lưỡi”: Có thể mà ông ta (tức tôi) cũng làm ra vẻ quan trọng, cũng đồi viết về những “bí mật” của nó cơ chứ. Các bạn suy nghĩ như vậy cũng không sai nhiều đâu. Nhưng các bạn chớ vội bỏ đi nhé, hãy cùng tôi, chúng ta cùng nhau tìm hiểu và khám phá. Tôi tin rằng những khám phá mà các bạn sẽ thấy, chỉ một chút nữa thôi sẽ vô cùng thú vị. Còn ngay bây giờ, mỗi bạn đều nên (dù chỉ một lần trong đời) ngồi bên máy tính, viết và chạy thử bài toán này. Thuật toán này vô cùng đơn giản, đầu vào là một số tự nhiên, đầu ra là … một dãy số.


Chúng ta hãy định nghĩa một cách chính xác thuật giải này.

Thuật toán 3N+1

Input: số tự nhiên k

1.Nếu k=1 thì dừng chương trình.

2.Nếu k chẵn thì đặt k=1/2; nếu k lẻ thì đặt k=3k+1.

3.Quay lại bước

Ví dụ: Nếu bắt đầu với k=34 thì thuật toán trên sẽ sinh ra dãy:

34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.

Như vậy thuật toán sẽ sinh ra một dãy số, nó chỉ dừng lại khi gặp số 1. Khảo sát, tìm hiểu thuật toán chính là việc khảo sát, khám phá những bí mật của dãy số này.

Câu hỏi thứ nhất: Dãy số của thuật toán trên có phải bao giờ cũng hữu hạn?

Câu hỏi này được đặt ra một cách rất tự nhiên. Hay nói một cách khác, thuật toán 3N+1 trên có phải là một thuật toán đúng đắn hay không

Ta định nghĩa hàm S như sau:

S(k)=số bước phải thực hiện của thuật toán cho giá trị ban đầu k, hay nói cách khác S(k) là độ dài của dãy số sinh bởi thuật toán 3N+1. Bằng cách định nghĩa hàm S như vậy, ta đưa toán của ta thành câu hỏi: Liệu hàm S có xác định với mọi số tự nhiên k hay không?

Rất tiếc và cũng rất kỳ lạ rằng câu hỏi tưởng chừng đơn giản đó cho đến tận ngày hôm nay vẫn chưa có câu trả lời: bài toán về tính đúng đắn của thuật toán 3N+1 vẫn còn bỏ ngỏ và như vậy tất cả chúng ta hãy còn có điều kiện để khám phá những bó ẩn còn tiềm tàng của thuật toán này. Chỉ biết rằng với những tính toán của tất cả các máy tính hiện đại nhất mà con người có được cho đến ngày hôm nay, thuật toán trên luôn luôn dừng, và như vậy giá trị S(k) và dãy số tương ứng vẫn được sinh ra liên tục, liên tục.

Câu hỏi thứ hai: Dãy số S(k) và bản thân các dãy được sinh ra bởi thuật toán 3N+1 sẽ tuân theo những qui luật nào?

Hôm nay, nhiệm vụ chính của tôi và các bạn là tìm hiểu các câu trả lời cho câu hỏi thứ hai này. Trước hết ta cần tính toán và in ra các giá trị của S(k). Vì giấy có hạn chúng tôi chỉ liệt kê ra S(k) với k ≤ 50, nhưng các bạn nên in ra cho mình những bảng với số lượng k càng lớn càng tốt (chẳng hạn k< 1000, 10000,..).

Bởi vì nhìn vào các bảng càng lớn chúng ta càng dễ khám phá những quy luật tiềm ẩn bên trong. Để cho việc tìm hiểu một cách dễ dàng hơn, chúng tôi liệt kê thêm giá trị lớn nhất sinh bởi dãy và giá trị lũy thừa của 2 đầu tiên xuất hiện trong dãy, các bạn sẽ thấy tất cả trong chúng đều có ý nghĩa về sau.

Bảng liệt kê các giá trị của S(k) với k từ 1 tới 50.

Các bạn hãy quan sát kỹ và sẽ tìm ra ngay một số qui luật:

1. Nhìn vào cột 4 của bảng trên ta thấy hầu hết là số 16. Điều đó thoạt tiên có vẻ hơi khó hiểu; tuy nhiên chỉ cần suy luận đôi chút thì ta sẽ lí giải được ngay: Rõ ràng lũy thừa đầu tiên cảu 2 chỉ có thể sinh ra ở chỗ “nhân 3 cộng 1”, do đó nó có dạng 3m+1 với m lẻ, hay 6n+4 với n là số tự nhiên tùy ý. Điều này chỉ đúng với những lũy thừa bậc chẵn của 2 như 4, 16, 64, 256, … Như vậy không một lũy thừa bậc lẻ nào của 2 có thể có mặt trong cột của bảng trên quá 1 lần. Điều đó giải thích sự vắng mặt của số 32 trong bảng, ngoại trừ trường hợp k=32.

2.Sự xuất hiện quá thưa thớt của 64 vẫn còn là một dấu hỏi nhưng nó sẽ được giải đáp sau.

3. Một số số có mặt trong cột giá trị lớn nhất khá thường xuyên: đó là các số 52, 88, 160 và 9232. Bốn số đó chiếm quãng đường một nửa các trường hợp với k từ 1 đến 50. Trong khi tìm qui luật xuất hiện của các giá trị lớn nhất, ta phát hiện một kết quả thú vị: đó là tất cả các số đó không có quá một thừa số nguyên tố khác 2. Rất tiếc qui luật này bị bác bỏ bởi số 340 trong trường hợp k=75. Tuy nhiên việc mở rộng bảng (đến k=100) không bác bỏ được sự thật là chỉ có một số số có xu hướng xuất hiện thường xuyên trong cột giá trị lớn nhất.

4. Một điều kì lạ nữa là ngoài ra, ngoại trừ một số trường hợp rất cá biệt (với S(k)>100), trong tất cả các trường hợp còn lại S(k)<35.

5. Ta nhận xét rằng có tồn tại một số dãy các số k liên tiếp có S(k) giống nhau, chẳng hạn S(14)=S(15)=17, S(28)=S(29)=S(30)=18, S(98)=S(99)=S(100)=S(101)=S(102)=25. Phải chăng đó lạo là một qui luật nữa?

Để minh họa ta xét 2 dãy với cặp k=14 và 15:

Để ý đến tính lặp lại của các số có cùng vị trí trong 2 dãy. Hiện tượng này gợi ý cho ta một cách tiếp cận mới với bài toán, đó là tìm qui luật của các lớp số có cùng độ dài s của dãy.

7. Kí hiệu C(s) là tập các số mà thuật toán kết thúc sau s bước. Như vậy, số k thuộc C(s) khi và chỉ khi S(k)=s. Ví dụ, C(0)= {1}, C(2)= {2}, …, C(5)= {32,5}. Như vậy ta lại có thêm một bài toán nữa: cần tính C(s).

Việc tính C(s) tốt nhất nên tiến hành theo phương pháp truy hồi như sau:

C(0)= {1}.

Giả sử C(s) = {k1, k2,…,kM}. Khi đó C(s+1) chứa:

1) số 2ki với mỗi ki thuộc C(s),

2) số (ki-1)/3 với mỗi ki thuộc C(s) có dạng 6n+4.

Kết quả của việc thực hiện thuật toán cho ta một cây mà một phần của nó thể hiện trên hình sau:

Mỗi mức của cây là một lớp C(s), s=0,1,2,.., còn đường đi từ mỗi đỉnh tới gốc chính là dãy số sinh bởi thuật toán

1.Hình vẽ này giải thích vì sao trong bảng trên số 64 lại ít gặp như vậy. Để số 64 là lũy thừa của 2 đầu tiên trong dãy thì k phải là một trong các số nằm trên nhánh cây trên 21, mà 21 chia hết cho 3 nên tất nhiên các số trên nhánh này không thể có dạng 6n+4 được. Do đó, từ công thức truy hồi trên ta suy ra số 64 là lũy thừa của 2 đầu tiên từng dãy khi và chỉ khi k có dạng 21.2m với m bất kì.

2.Gọi n(s) là số các phần tử của tập hợp C(s). Thuật toán truy hồi để tính các lớp C(s) dẫn tới công thức tuy hồi tính n(s).

Giả sử e(s) và o(s) tương ứng là số các phần tử chẵn và lẻ của C(s) thì n(s)=e(s)+o(s). Hơn nữa với mỗi số s ta có e(s)=n(s-1) và mỗi số lẻ trong C(s) thu được từ số dạng 6n+4 trong C(s-1).

Giả sử ràng khoảng một phần ba các số chẵn trong mỗi tập C(s) có dạng 6n+4 (điều này không hoàn toàn hiển nhiên, chẳng hạn trên cây ở hình trên ta thấy trong mỗi tập C(s) các số lẻ ít hơn các số chẵn, các bạn thử kiểm nghiệm lấy xem!).

Khi đó ta được o(s)=e(s-1)/3, và vì e(s-1)=n(s-2) nên ta thu được công thức truy hồi sau đây:

n(s)=n(s-1)+n(s-2)/3

Tất nhiên công thức trên chỉ là xấp xỉ nhưng thật tuyệt vời phải không các bạn.

Nếu bây giờ ta đặt xấp xỉ n(k)=hxk với h là một hằng số nào đó thì từ công thức truy hồi trên ta có:

từ đó suy ra

Vậy ta có công thức sau:

với h là một hằng số.

Như vậy, n(s) tăng như một hàm mũ với cơ số

điều này hoàn toàn phù hợp với các giá trị của tỉ số n(s)/n(s-1) trong bảng sau:

Phỏng dịch theo “Computer Approaches to Mathematical Problems” của Nievergelt, Farrar và Reingold.


URL của bài viết này::http://www.vnschool.net/modules.php?name=News&file=article&sid=489