【发布时间】:2012-12-20 17:06:26
【问题描述】:
我正在尝试使用 Mathematica 解决以下问题:
通过算术运算{+,-,*,/}、求幂和括号无法从集合{2,3,4,5,6,7,8} 中获得的最小正整数是多少。集合中的每个数字必须只使用一次。不允许一元运算(例如,如果不使用 0,则 1 不能转换为 -1)。
例如,号码1073741824000000000000000 可通过(((3+2)*(5+4))/6)^(8+7) 获得。
我是 Mathematica 的初学者。我编写的代码我相信可以解决集合 {2,3,4,5,6,7} 的问题(我的答案是 2249),但是我的代码效率不足以处理集合 {2,3,4,5,6,7,8}。 (我的代码已经在 {2,3,4,5,6,7} 集合上运行需要 71 秒)
我非常感谢使用 Mathematica 解决这个更困难的问题的任何提示或解决方案,或关于如何加快现有代码速度的一般见解。
我现有的代码使用暴力递归方法:
(* 这将一组 1 个数字的组合定义为该 1 个数字的集合 *)
combinations[list_ /; Length[list] == 1] := list
(* 这测试是否可以对两个数字求幂,包括(有点)任意限制以防止溢出 *)
oktoexponent[number1_, number2_] :=
If[number1 == 0, number2 >= 0,
If[number1 < 0,
(-number1)^number2 < 10000 \[And] IntegerQ[number2],
number1^number2 < 10000 \[And] IntegerQ[number2]]]
(* 这需要一个列表并删除分母大于 100000 *)
cleanup[list_] := Select[list, Denominator[#] < 100000 &]
(* 这定义了一组 2 个数字的组合 - 并返回一组通过 + - * / 由 oktoexponent 和清理规则过滤的应用获得的所有可能数字 *)
combinations[list_ /; Length[list] == 2 && Depth[list] == 2] :=
cleanup[DeleteCases[#, Null] &@DeleteDuplicates@
{list[[1]] + list[[2]],
list[[1]] - list[[2]],
list[[2]] - list[[1]],
list[[1]]*list[[2]],
If[oktoexponent[list[[1]], list[[2]]], list[[1]]^list[[2]],],
If[oktoexponent[list[[2]], list[[1]]], list[[2]]^list[[1]],],
If[list[[2]] != 0, list[[1]]/list[[2]],],
If[list[[1]] != 0, list[[2]]/list[[1]],]}]
(* 这扩展了组合以使用集合集 *)
combinations[
list_ /; Length[list] == 2 && Depth[list] == 3] :=
Module[{m, n, list1, list2},
list1 = list[[1]];
list2 = list[[2]];
m = Length[list1]; n = Length[list2];
cleanup[
DeleteDuplicates@
Flatten@Table[
combinations[{list1[[i]], list2[[j]]}], {i, m}, {j, n}]]]
(*对于给定的集合,partition返回所有partition的集合成两个非空子集*)
partition[list_] := Module[{subsets},
subsets = Select[Subsets[list], # != {} && # != list &];
DeleteDuplicates@
Table[Sort@{subsets[[i]], Complement[list, subsets[[i]]]}, {i,
Length[subsets]}]]
(* 这最终扩展了组合以适用于任何大小的集合 *)
combinations[list_ /; Length[list] > 2] :=
Module[{partitions, k},
partitions = partition[list];
k = Length[partitions];
cleanup[Sort@
DeleteDuplicates@
Flatten@(combinations /@
Table[{combinations[partitions[[i]][[1]]],
combinations[partitions[[i]][[2]]]}, {i, k}])]]
Timing[desiredset = combinations[{2, 3, 4, 5, 6, 7}];]
{71.5454, Null}
Complement[
Range[1, 3000], #] &@(Cases[#, x_Integer /; x > 0 && x <= 3000] &@
desiredset)
{2249, 2258, 2327, 2509, 2517, 2654, 2789, 2817, 2841, 2857, 2990, 2998}
【问题讨论】:
-
好吧,如果你向我们展示你的代码而不是它的粗略草图,我们中的一些人会剪切粘贴和摆弄。
-
不知何故这听起来像是一个学校作业..
-
我现在将发布我的代码 - 最初没有发布,只是因为我知道我是一个初学者,并且预计需要完全重写最佳代码。 Jari,不太清楚该说什么——不是——我正在努力学习 Mathematica,并且一直在通过 Project Euler 解决问题作为这样做的一种方式。这也是我亲自为自己设定的问题。
-
我在这里回答了类似的问题stackoverflow.com/a/3948113/353410
-
@Royce,确认一下,这不是 projecteuler.net 的问题,对吗?换句话说,你知道这个问题没有在线解决方案吗?我的想法:我认为您不能安全地丢弃较大的中间结果(溢出),因为它们可能会再次变小。我会建议一种符号方法(不一定使用 Mathematica),您可以在其中简化每一轮的符号(即“2*3”和“3*2”是相同的)。