昨晚实在无聊,半夜爬起来看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 + ……
而一个无理数可能是不能表示为有限个单位分数之和的。因为只要将这有限个分数通分就能将这个无理数写成某个分式,那么它就不是无理数了。
然后的然后,我还没想出来-_-!