长度为 9 的 999 有 44 个解:
39149*+**
39166*+**
39257*+**
39548*+**
39756*+**
39947*+**
39499**+*
39669**+*
39949**+*
39966**+*
93149*+**
93166*+**
93257*+**
93548*+**
93756*+**
93947*+**
93269**+*
93349**+*
93366**+*
93439**+*
93629**+*
93636**+*
93926**+*
93934**+*
93939+*+*
93948+*+*
93957+*+*
96357**+*
96537**+*
96735**+*
96769+*+*
96778+*+*
97849+*+*
97858+*+*
97867+*+*
99689+*+*
956*99*+*
968*79*+*
39*149*+*
39*166*+*
39*257*+*
39*548*+*
39*756*+*
39*947*+*
编辑:
我正在进行一些搜索空间修剪改进,很抱歉我没有立即发布。Erlnag 中有脚本。原来的 999 需要 14 秒,但这个在 190 毫秒左右。
编辑2:
9999 有 1074 个长度为 13 的解。需要 7 分钟,其中一些如下:
329+9677**+**
329+9767**+**
338+9677**+**
338+9767**+**
347+9677**+**
347+9767**+**
356+9677**+**
356+9767**+**
3147789+***+*
31489+77***+*
3174789+***+*
3177489+***+*
3177488*+**+*
C 中有一个版本对状态空间进行了更积极的修剪,并且只返回一个解决方案。它要快得多。
$ time ./polish_numbers 999
Result for 999: 39149*+**, length 9
real 0m0.008s
user 0m0.004s
sys 0m0.000s
$ time ./polish_numbers 99999
Result for 99999: 9158*+1569**+**, length 15
real 0m34.289s
user 0m34.296s
sys 0m0.000s
harold报告说他的 C# bruteforce版本在 20 年代产生了相同的数字,所以我很好奇我是否可以改进我的。我通过重构数据结构尝试了更好的内存利用率。搜索算法主要适用于解决方案的长度并且它存在,所以我将这些信息分成一个结构(best_rec_header
)。我也提出了解决方案,因为树枝在另一个(best_rec_args
)中分开。这些数据仅在给定数字的新更好解决方案时使用。有代码。
Result for 99999: 9158*+1569**+**, length 15
real 0m31.824s
user 0m31.812s
sys 0m0.012s
它仍然太慢了。所以我尝试了一些其他版本。首先,我添加了一些统计数据来证明我的代码没有计算所有较小的数字。
Result for 99999: 9158*+1569**+**, length 15, (skipped 36777, computed 26350)
然后我尝试更改代码以首先计算+
更大数字的解决方案。
Result for 99999: 1956**+9158*+**, length 15, (skipped 0, computed 34577)
real 0m17.055s
user 0m17.052s
sys 0m0.008s
它几乎快了两倍。但是还有另一个想法,有时我可能会放弃为受当前best_len
限制限制的某些数字寻找解决方案。所以我试图让小数字(最多一半n
)无限制(注意255
作为best_len
第一个操作数查找的限制)。
Result for 99999: 9158*+1569**+**, length 15, (skipped 36777, computed 50000)
real 0m12.058s
user 0m12.048s
sys 0m0.008s
很好的改进,但是如果我通过迄今为止找到的最佳解决方案来限制这些数字的解决方案怎么办。它需要某种计算全局状态。代码变得更复杂,但结果更快。
Result for 99999: 97484777**+**+*, length 15, (skipped 36997, computed 33911)
real 0m10.401s
user 0m10.400s
sys 0m0.000s
它甚至能够计算出十倍大的数字。
Result for 999999: 37967+2599**+****, length 17, (skipped 440855)
real 12m55.085s
user 12m55.168s
sys 0m0.028s
然后我决定也尝试蛮力方法,这甚至更快。
Result for 99999: 9158*+1569**+**, length 15
real 0m3.543s
user 0m3.540s
sys 0m0.000s
Result for 999999: 37949+2599**+****, length 17
real 5m51.624s
user 5m51.556s
sys 0m0.068s
这表明,那是永恒的事情。当蛮力方法从更好的矢量化、更好的 CPU 缓存利用率和更少的分支中获得优势时,现代 CPU 尤其如此。
无论如何,我认为有一些更好的方法可以更好地理解数论或通过算法进行空间搜索,例如 A* 等等。对于非常大的数字,使用遗传算法可能是个好主意。
编辑3:
哈罗德提出了一个新的想法,以消除尝试大量资金的做法。我已经在这个新版本中实现了它。它快了一个数量级。
$ time ./polish_numbers 99999
Result for 99999: 9158*+1569**+**, length 15
real 0m0.153s
user 0m0.152s
sys 0m0.000s
$ time ./polish_numbers 999999
Result for 999999: 37949+2599**+****, length 17
real 0m3.516s
user 0m3.512s
sys 0m0.004s
$ time ./polish_numbers 9999999
Result for 9999999: 9788995688***+***+*, length 19
real 1m39.903s
user 1m39.904s
sys 0m0.032s