Algorithm 从给定的数中,确定三个闭合数,其乘积为原始数

Algorithm 从给定的数中,确定三个闭合数,其乘积为原始数,algorithm,math,language-agnostic,numbers,Algorithm,Math,Language Agnostic,Numbers,我有一个数字n,我想找到三个乘积为n但尽可能接近的数字。也就是说,如果n=12,那么我想得到3,2,2,而不是6,1,2 另一种思考方法是,如果n是长方体的体积,那么我想求边的长度,以便使长方体尽可能像一个立方体(也就是说,长度尽可能相似)。这些数字必须是整数 我知道不太可能有一个完美的解决方案,我很乐意使用一些大部分时间都能给出一个好答案的东西,但我就是想不出这个算法该怎么做。有什么想法吗?这是我的第一个算法草图,假设n相对较小: 计算n的值 选择三个最大的,并将它们分配到f1,f2,f3。

我有一个数字
n
,我想找到三个乘积为
n
但尽可能接近的数字。也就是说,如果n=12,那么我想得到3,2,2,而不是6,1,2

另一种思考方法是,如果
n
是长方体的体积,那么我想求边的长度,以便使长方体尽可能像一个立方体(也就是说,长度尽可能相似)。这些数字必须是整数


我知道不太可能有一个完美的解决方案,我很乐意使用一些大部分时间都能给出一个好答案的东西,但我就是想不出这个算法该怎么做。有什么想法吗?

这是我的第一个算法草图,假设
n
相对较小:

  • 计算
    n
    的值
  • 选择三个最大的,并将它们分配到
    f1
    f2
    f3
    。如果因子少于三个,则分配
    1
  • 按降序循环剩余的因子,将它们乘以当前最小的分区

编辑

让我们取
n=60

它的主要因素是
5322

设置
f1=5
f2=3
f3=2

剩余的
2
乘以
f3
,因为它是最小的

我们的结果是
5*4*3=60


编辑

此算法不会找到最佳值,请注意注释:


考虑17550=2*3*3*5*5 * 13. 当最佳值为25、26、27时,您的算法将给出15、30、39


编辑

好的,这是我的第二个算法草图,带有稍微好一点的启发式:

  • 将列表
    L
    设置为
    n
    的值
  • r
    设置为
    n
    的值
  • 创建三个因素的集合
    F
    ,初始设置为
    1
  • 按降序迭代素数因子:
    • 尝试将当前系数
      L[i]
      与每个系数按降序相乘。
      • 如果结果小于
        r
        ,则执行乘法并继续下一步 首要因素
      • 如果没有,请尝试下一个
        F
        。如果超出
        F
        s,则与最小值相乘
这适用于
17550

n=17550
L=13,5,5,3,3,3,2
r=25.98

F = { 1, 1, 1 }
迭代1:

  • F[0]*13
    小于
    r
    ,将
    F
    设置为
    {13,1,1}
迭代2:

  • F[0]*5=65
    大于
    r
  • F[1]*5=5
    小于
    r
    ,将
    F
    设置为
    {13,5,1}
迭代3:

  • F[0]*5=65
    大于
    r
  • F[1]*5=25
    小于
    r
    ,将
    F
    设置为
    {13,25,1}
迭代4:

  • F[0]*3=39
    大于
    r
  • F[1]*3=75
    大于
    r
  • F[2]*3=3
    小于
    r
    ,将
    F
    设置为
    {13,25,3}
迭代5:

  • F[0]*3=39
    大于
    r
  • F[1]*3=75
    大于
    r
  • F[2]*3=9
    小于
    r
    ,将
    F
    设置为
    {13,25,9}
迭代6:

  • F[0]*3=39
    大于
    r
  • F[1]*3=75
    大于
    r
  • F[2]*3=27
    大于
    r
    ,但它是我们能得到的最小F。将
    F
    设置为
    {13,25,27}
第7次迭代:

  • F[0]*2=26
    r
    大,但这是我们能得到的最小F。将
    F
    设置为
    {26,25,27}
    • 编辑 这里有一个简短的解释,使用更高效的代码,大大简化了事情。W先生也提出了一些建议。总体逻辑保持不变

      假设至少有3个素数因子n

    • 查找n的素数因子的三元组
      KSetPartitions
      列表
    • 将每个子集内的每个元素(素数因子)相乘,以产生n的三个因子的所有可能组合(当它们相乘时产生n)。你可以把除数想象成一个正交平行六面体的长度、宽度和高度
    • 最靠近立方体的平行六面体的对角线空间最短。将每种情况下三个除数的平方和取最小值
      以下是Mathematica中的代码:

      Needs["Combinatorica`"]
      g[n_] := Module[{factors = Join @@ ConstantArray @@@ FactorInteger[n]},
        Sort[Union[Sort /@ Apply[Times, Union[Sort /@ 
            KSetPartitions[factors, 3]], {2}]] 
            /. {a_Integer, b_Integer, c_Integer} :>  
                 {Total[Power[{a, b, c}, 2]], {a, b, c}}][[1, 2]]]
      

      它可以处理相当大的数,但随着n的因子数的增加,速度会大大减慢。下面的示例显示了240、2400、…24000000的计时。 考虑到一个因子在一个除数中出现多次的情况,原则上可以加快这一速度。我还不知道怎么做

      In[28]:= g[240]
      
      Out[28]= {5, 6, 8}
      
      In[27]:= t = Table[Timing[g[24*10^n]][[1]], {n, 6}]
      
      Out[27]= {0.001868, 0.012734, 0.102968, 1.02469, 10.4816, 105.444}
      

      正如安德斯·林达尔(Anders Lindahl)所追求的那样,也许有一种聪明的方法可以找到最紧密的三胞胎,但我将重点介绍一种更基本的方法

      如果我生成了所有的三元组,那么我可以根据需要过滤它们,所以我将从这里开始。我所知道的生成这些函数的最佳方法是使用递归:


      此函数
      f
      接受两个整数参数,即系数
      n
      的数量和产生系数
      k
      的数量

      这一节是
      #[[2;];;⌈ 长度@#/k⌉ ]] & @ 除数@n
      使用
      除数
      生成
      f[n_, 1] := {{n}}
      
      f[n_, k_] := Join @@
          Table[
            {q, ##} & @@@ Select[f[n/q, k - 1], #[[1]] >= q &],
            {q, #[[2 ;; ⌈ Length@#/k ⌉ ]] & @ Divisors @ n}
          ]
      
      In[]:= f[240, 3]
      
      Out[]= {{2, 2, 60}, {2, 3, 40}, {2, 4, 30}, {2, 5, 24}, {2, 6, 20},
              {2, 8, 15}, {2, 10, 12}, {3, 4, 20}, {3, 5, 16}, {3, 8, 10},
              {4, 4, 15}, {4, 5, 12}, {4, 6, 10}, {5, 6, 8}}
      
      Clear[poly, disc, f]
      poly = x^3 + a x^2 + b x + c;
      disc = Discriminant[poly, x];
      f[n_Integer] := 
       Module[{p, \[CapitalDelta] = disc /. c -> -n}, 
        p = poly /. 
           Maximize[{a, \[CapitalDelta] >= 0, 
              b > 0 && a < 0 && {a, b} \[Element] Integers}, {a, b}][[
            2]] /. c -> -n;
        Solve[p == 0]
        ]