昨晚實在無聊,半夜爬起來看BBC的《數學的故事》。當那個長得像Daniel Craig的大叔以極其詭異的手法解決了古埃及勞苦人民的分餅問題后,我瞬間被震撼了,雖然好像自己以前曾經做過,但是一點印象都沒了。
幾個概念:
- 我們把0到1之間的分數叫做真分數;
- 分子為1的真分數稱為單位分數。
問題描述:
如何將任意真分數x拆解為有限個單位分數之和?
考慮到可能有多個解法,在此我們要求單位分數盡可能大。
我們首先考慮的是用1/2,1/3,1/4,……一個個去試,如果這個單位分數1/n比x小,1/n就入選了。接著用同樣方法從1/(n+1)開始找x - 1/n的解。能不能一次定位n呢?
既然要求x - 1/n > 0 且n盡可能小,那么n就是大于1/x的最小整數,即n = ceiling[1/x]。以下是Mathematica解法:
aux[x_] := 1/Ceiling[1/x]
toS := ToString[#, InputForm] &
g[x_] :=
If[IntegerQ[1/x], x // toS,
(f[x] // toS) <> "+" <> g[x - aux[x]]]
aux()和toS()這兩個函數都是打醬油的,g()才是主角。如果x本身就是單位分數,那么省事了(這也是遞歸的終點),但如果不是,則照上面的辦法求解。
P.S. 好久沒用Mathematica了,還是很快就上手了。但發現幾個問題:
- Mathematica的自定義函數名不允許含下劃線,因為下劃線有特殊含義(以前專門研究過,可惜每次過后就忘)。這樣我就不能像Ruby那樣把函數取名為to_s,有點小不爽。
- Mathematica好像不能像Ruby那樣在字符串內求值#{...}。所以我只好用丑陋的StringJoin(即<>)。
接下來,很自然地想問:這個算法能不能保證在有限步內終止,即真分數能不能表示為有限個盡可能大的單位分數之和。注意,聯想到無窮級數,你能很輕易找到某個真分數可以表示為無窮個單位分數之和,比如1/3 = 1/4 + 1/16 + 1/64 + ……
而一個無理數可能是不能表示為有限個單位分數之和的。因為只要將這有限個分數通分就能將這個無理數寫成某個分式,那么它就不是無理數了。
然后的然后,我還沒想出來-_-!