孫學進 王德貴
有人問我,天天研究數學問題,數學到底哪里有趣了?數學之美又在哪里?其實,當你研究深入后,會發現數學真的很奇妙!也有很多未解之謎,今天我們來了解一下數學黑洞“6174”。
數學黑洞,就是無論怎樣設值,在規定的處理法則下,最終都將得到固定的一個值,再也跳不出去了,就像宇宙中的黑洞可以將任何物質包括光都牢牢吸住,不使它們逃脫一樣。
數學黑洞6174,又稱卡普雷卡爾(Kaprekar)常數。內容是:
取一個4位數(4個數字全相同的除外),將該數的4個數字重新組合,形成可能的最大數和可能的最小數,再將兩者之間的差求出來;對此差值重復同樣過程,不足4位在末位補0,最后你總是會得到6174陷入卡普雷卡爾黑洞,而且經過我的驗算到達這個黑洞最多需要7個步驟(注:百度百科上說,是14個步驟,存疑)。
今天我們用Python、圖形化(SC)和APPInventor來做驗證。
有趣的數學問題,加上Python編程,真是絕妙的搭配!近期也一直在和大家分享我的學習過程。在Python等級考試4級學習中,遇到了這個問題,經過一段時間的研究、探討和分析感到收獲頗多,分享給大家,希望能提高你學習Python的興趣。
這是一個驗證的問題,也要解決以下3個問題。
一是輸入任意一個4位數(不包含全部相同的數字),驗證最后經過運算是不是都得到“6174”;二是在一定范圍內,是不是都能得到“6174”;三是得到“6174”最多需要多少個步驟。
首先要將4位數分解開單個數字,存儲在新列表中,然后排序列表,輸出最大和最小數,做差,然后再存儲在新列表中,循環操作,直到得到6174,程序結束。
通過三種編程方法,分別驗證,求解。
程序涉及到的是中國電子學會編程等級考試四級內容。
即是輸入一個數字不完全相同的4位數,進行驗證,看看能不能得到6174,需要幾步。
1.遞推法
輸入一個4位數,但4個數字不能完全相同,將其轉換為列表,排序、連接、轉換出最大值和最小值,做差,再轉換為列表,如果不夠4位,則添加“0”,進行下一輪循環,直到得到“6174”,然后輸出轉換用了多少次(圖1)。

下面是驗證“1112”的輸出結果(圖2)。

2.遞歸法
遞歸與遞推不同之處,是調用了自身,達到循環的目的。過程和方法與遞推類似。
不同的是,遞推算法中第7行的n=0,去掉了,這是因為如果加上這行,每次調用自身的時候,n都會歸0,不能計數,所以必須先設置n=0,然后在自定義函數中用“global n”(圖3)。

兩種方法驗證的結果是完全一樣的。
即是驗證一定范圍內所有數字不完全相同的4位數,看看能不能得到6174,在這個范圍內需要最多的步數是多少。
1.遞推法
通過遞推法驗證(圖4)。

在1100-1120范圍內的驗證結果。在“1111”時提示數字完全一樣,不能驗證(圖5)。

在1000-9999范圍內的遞推法驗證,即所有4位數的驗證結果。在數字完全一樣時,給出提示,從驗證結果看,所有不完全相同的4位數,經過運算均可以得到“6174”,運算的最多次數是“7”。
2.遞歸法
遞歸法,和遞推法一樣,也是在驗證的基礎上,驗證一定范圍內的所有整數,經過運算是不是都能得到“6174”,并輸出最多的運算次數。不同的是遞歸是通過調用自身,達到循環的目的。
同樣,遞歸法需要將遞推算法中的n=0去掉,而在遍歷前設置n=0,然后在自定義函數中設置為“global n”。m為最大次數變量(圖6)。

在1100-1120范圍內的驗證結果。在“1111”時提示數字完全一樣,不能驗證。驗證結果和遞推算法一樣。
在1000-9999范圍內的遞歸法驗證,即所有4位數的驗證結果。在數字完全一樣時,給出提示,從驗證結果看,所有不完全相同的4位數,經過運算均可以得到“6174”,運算的最多次數是“7”。我們看到,兩種方法的驗證結果是完全一樣的(圖7)。

1.遞推法
將前面用遞推法的驗證和范圍的兩個程序合并在一起,但要考慮兩種方法共同調用了自定義函數,所以需要將部分打印語句保留。
開始是選擇“驗證”還是“范圍”,然后進入循環和調用,輸入相關數據,進行運算,如果選擇“退出”,則程序結束(圖8、圖9)。


2.遞歸法
遞歸法與遞推類似,是將前面用遞歸法的驗證和范圍的兩個程序合并在一起,同樣,開始時還是選擇“驗證”或是“范圍”,然后進入循環和調用,輸入相關數據,進行運算,如果選擇“退出”,則程序結束(圖10、圖11)。


在1100-1120范圍內的驗證結果。在“1111”時提示數字完全一樣,不能驗證。最后輸出運算的最多次數。
驗證和范圍做在了一起,下面一一講解。
1.初始化
輸入想要驗證的4位數,運算次數,都顯示在屏幕上, 差值會隨著運算改變,直到6174(圖12)。

2.輸入數據的檢驗
如果輸入的數值不是4位數,則提示輸入(圖13)。

如果在1000-9999之間則開始運算。
3.驗證并顯示
先將輸入的數值保存在變量“差”中,然后將其每個數字添加到列表“list”中,再調用自定義積木,排序并求最大和最小值(圖14)。

如果差為“0”,即是數字相同時,將差設置為“6174”,因為循環的條件是差為“0”。最后提示運算了多少次。
4.自定義積木
自定義積木是為了運算的方便,也是為了程序設計方便。首先檢查列表長度,如果小于4則添加“0”補足4位,否則運算會出錯。
然后對4個數字進行從大到小排序,最后是輸入最大值和最小值,以便計算時調用。同時清空數據列表,將4個變量初始化。
1.初始化
設置需要顯示的變量,直觀,明了。
輸入范圍的開始值和結束值。最后顯示運算次數中的最大次數值。
2.驗證并顯示
在范圍內依次取值,做驗證即可。
循環方法是次開始值增加1,依次驗證,當開始值大于結束值時,停止循環。所以循環是包括開始和結束兩個值的(圖15)。

注意幾個問題:
一是數字全部相同的,要停止運算,進入到下一個循環,這里直接設置為6174(驗證時停止循環的條件);
二是保存運算次數的最大值,程序運算完,顯示出來(圖16)。

3.范圍和驗證合并
首先要將驗證和范圍都做成自定義積木,然后設計一個選擇菜單,是做一個數據驗證,還是驗證一個范圍內的所有數據,通過選擇確定,如果輸入其他則報錯。這和Python程序設計思路是一樣的。
1.UI設計
界面如圖,無須做過多修飾,組件任意組合,能完成驗證就可以(圖17)。

2.變量和初始化
設置程序運行需要的變量,將程序初始化(圖18)。

3.定義過程:建立數據列表
即可將4位數的4個數字添加到列表中,然后判斷是不是數字全部相同,如果全部相同,則做標記(圖19)。

4.定義過程:數字排序
將4個數字從大到小排序,然后輸出最大值和最小值。
5.提交
判斷輸入是否為空,是否不是4位數,如果有一項不滿足,就會提示輸入有誤(圖20)。

如果輸入正確,則判斷是不是數字相同,如果數字相同,則提示不能輸入相同數字的數(圖21)。

如果數字不相同,則進入循環,直到結果為6174。
首先調用數字排序,然后計算差值,將運算次數加1,顯示運算過程,同時再次調用建立數據列表,將計算出的差值依次添加到數據列表中,然后進入下一個循環,直到差值為6174(圖22)。

完整的程序請在壹零社公眾號下載。
測試結果(圖23):

1.UI設計
界面設計與驗證相似,就是多加了幾個組件(圖24)。

2.初始化
其實設計時,考慮了兩種情況合并的程序(圖25)。

3.定義過程
定義過程建立數據列表和數字排序,和驗證程序的一樣。
4.提交
在一定范圍內驗證每個4位數是不是經過運算都能得到6174。
所以開始程序還是要檢驗輸入數據的正確性,然后進行循環,從開始值依次加1到結束值,一一驗證。最后顯示運算的最大次數,與Python和Scratch相同。
驗證過程基本和之前的一樣。首先顯示當前驗證的值,然后調用“建立數據列表”,如果數字相同則提示(圖26)。

否則就循環執行驗證,直到差值為“6174”,同時顯示本次運算的次數。如果運算次數大于最大次數,則將最大次數賦值為次數。
完整的程序請在壹零社公眾號下載。
測試結果(圖27):

1.UI設計
界面設計與“范圍”相同,本例在最初設計時,即考慮了合并狀態。
2.變量和初始化
這個與驗證時一樣。
3.定義過程
這個也是一樣的,建立數據列表和數字排序兩個過程。
4.驗證
驗證4位數時,點擊按鈕,即設置初始化值。當前使用的按鈕功能,會顯示為紅色背景(圖28)。

5.范圍
需要驗證一定范圍內的所有4位數時,點擊按鈕,即設置初始化值。當前使用的按鈕功能,會顯示為紅色背景。
6.提交
提交按鈕,要先判斷是驗證狀態,還是范圍狀態,需要判斷驗證標記。如果驗證標記為“真”,則進行驗證界面,否則進入范圍驗證界面,兩個程序如前(圖29)。

由于前面分別測試過,所以這里不再測試。
三種方法的測試速度都非常快。由于軟件的局限,設計思路稍有不同,但均完成了驗證任務。
三種程序也可以進行改進,比如,每一步都是自己來完成計算,即輸入一個數后,自己取最大和最小值,再做差,依次運算來驗證。或是隨時查看程序的驗證過程。這里給出一個簡單的Python程序示例,自定義函數與遞推的驗證程序一樣。運行結果如下(圖30)。

如果輸入有誤,7次之內沒有驗證出來,則提示輸入有錯誤,沒有完成驗證。
本文是我自己的研究過程和心得,有不妥之處,請各位老師和同學斧正!