SML中n-1个元素的LCM

时间:2018-08-18 08:09:13

标签: sml lcm

我具有以下功能来计算列表中所有元素的LCM。是否有任何计算每个(n-1)个子集的每个LCM并将其存储在列表中的提示?

fun modulo (_,0) = 0
  | modulo (0,_) = 0
  | modulo (x,y) = if y > x then x else
    let
      fun getMod(z) = if z >= y then getMod(z-y) else z
    in
      getMod(x)
    end

fun lcm (0,_) = 0
  | lcm (_,0) = 0
  | lcm (x,y) = 
    let
      fun findLcm (base,mult,v) =
          if modulo(mult,v) = 0
          then mult
          else findLcm(base,mult+base,v)
    in
      if x > y then findLcm(x,x,y) else findLcm(y,y,x)
    end

fun ekp(xs) =
    case xs of
         []       => 1
       | (x::xs') => lcm(x,ekp(xs'))

1 个答案:

答案 0 :(得分:1)

假定“ S的(n-1)个子集”表示 {S \ {x} | x∈S} S 的子集的集合,其中对于 S 的每个元素都删除了一个元素,您可以轻松生成 least首先通过生成集合,然后对每个子集应用最小公倍数算法,对每个子集的公倍数

这是生成最小公倍数的较短方法:

fun gcd (a, 0) = a
  | gcd (a, b) = gcd (b, a mod b)

fun lcm (a, b) = (a * b) div (gcd (a, b))

val lcm_list = foldl lcm 1

函数lcm_list与您的函数ekp相对应。

要获取从每个元素中删除一个元素的子集列表(假定没有重复项):

fun curry f x y = f (x, y)
fun subsets1 [] = []
  | subsets1 (x::xs) = xs :: map (curry op:: x) (subsets1 xs)

并为每个子集生成最小公倍数

- subsets1 [3,4,5];
> val it = [[4, 5], [3, 5], [3, 4]] : int list list
- map lcm_list (subsets1 [3,4,5]);
> val it = [20, 15, 12] : int list

也就是说,发现 {3,4,5} 的(n-1)个子集是 {{4,5},{3,5},{3 ,4}} ,并且每个(n-1)个子集最小公倍数 {lcm(4,5), lcm(3,5),lcm(3,4)} = {20,15,12} 。在这一点上,可能已经进行了一些多余的工作。对于任何更大的列表,子集集将具有大量重叠。例如,

- subsets1 [3,4,5,6,7,8];
> val it =
    [ [4, 5, 6, 7, 8],
      [3, 5, 6, 7, 8],
      [3, 4, 6, 7, 8],
      [3, 4, 5, 7, 8],
      [3, 4, 5, 6, 8],
      [3, 4, 5, 6, 7] ] : int list list

使用上述方法,我们将计算lcm (3, 4) = 12倍四次,lcm (12, 5) = 60倍三倍,依此类推。您可能会受益于applying memoization到{ {1}}函数,尽管它并不十分昂贵。