我正在尝试使用Mathematica解决以下问题:
通过算术运算{2,3,4,5,6,7,8}
,取幂和括号从集合{+,-,*,/}
无法获得的最小正整数是多少。集合中的每个数字必须只使用一次。不允许一元操作(例如,1不能转换为-1而不使用0)。
例如,号码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[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}
答案 0 :(得分:0)
这是无益的,但今天我的无用bab呀学语的配额不足:
(* it turns out the symbolizing + * is not that useful after all *)
f[x_,y_] = x+y
fm[x_,y_] = x-y
g[x_,y_] = x*y
gd[x_,y_] = x/y
(* power properties *)
h[h[a_,b_],c_] = h[a,b*c]
h[a_/b_,n_] = h[a,n]/h[b,n]
h[1,n_] = 1
(* expand simple powers only! *)
(* does this make things worse? *)
h[a_,2] = a*a
h[a_,3] = a*a*a
(* all symbols for two numbers *)
allsyms[x_,y_] := allsyms[x,y] =
DeleteDuplicates[Flatten[{f[x,y], fm[x,y], fm[y,x],
g[x,y], gd[x,y], gd[y,x], h[x,y], h[y,x]}]]
allsymops[s_,t_] := allsymops[s,t] =
DeleteDuplicates[Flatten[Outer[allsyms[#1,#2]&,s,t]]]
Clear[reach];
reach[{}] = {}
reach[{n_}] := reach[n] = {n}
reach[s_] := reach[s] = DeleteDuplicates[Flatten[
Table[allsymops[reach[i],reach[Complement[s,i]]],
{i,Complement[Subsets[s],{ {},s}]}]]]
这里的一般想法是避免计算权力(这是 昂贵且不可交换),同时使用 加法/乘法的交换性/相关性以减少 达到基数[]。
以上代码也可在以下网址获得:
https://github.com/barrycarter/bcapps/blob/master/playground.m#L20
以及其他无用的代码,数据和幽默的字面意义。
答案 1 :(得分:0)
我认为你的问题的答案在命令Groupings
中。这允许您创建列表的二叉树。二进制树非常有用,因为您允许的每个操作Plus, Subtract, Times, Divide, Power
都有两个参数。例如。
In> Groupings[3,2]
Out> {List[List[1,2],3],List[1,List[2,3]]}
因此,我们需要做的就是用允许操作的任意组合替换List
。
然而,Groupings
似乎是全能的,因为它可以选择这样做。想象一下,您有两个函数foo
和bar
,并且都有2
个参数,那么您可以将所有组合设为:
In> Groupings[3,{foo->2,bar->2}]
Out> {foo[foo[1,2],3],foo[1,foo[2,3]],foo[bar[1,2],3],foo[1,bar[2,3]],
bar[foo[1,2],3],bar[1,foo[2,3]],bar[bar[1,2],3],bar[1,bar[2,3]]}
现在可以计算我们的组合数量:
In> Groupings[Permutations[#],
{Plus->2,Subtract->2,Times->2,Divide->2,Power->2}
] &@ {a,b,c,d,e};
In> Length@%
In> DeleteDuplicates@%%
In> Length@%
Out> 1050000
Out> 219352
这意味着对于5个不同的数字,我们有219352个独特的组合。
可悲的是,由于溢出,除零或下溢,许多这些组合无法评估。但是,要删除哪些是不明显的。价值a^(b^(c^(d^e)))
可能很大,或者很小。分数幂可以导致完美的根源,大数量的分裂可以变得完美。
In> Groupings[Permutations[#],
{Plus->2,Subtract->2,Times->2,Divide->2,Power->2}
] &@ {2, 3, 4};
In> Union[Cases[%, _?(IntegerQ[#] && # >= 0 &)]];
In> Split[%, #2 - #1 <= 1 &][[1]]
Out> {1, 2, 3, 4, 5, 6}