【问题标题】:Implementing a factorisation method in Haskell在 Haskell 中实现分解方法
【发布时间】:2009-12-06 14:41:40
【问题描述】:

我在 Project Euler 做question 266,经过一番搜索,发现this method 可以快速找到一个数的因数。你要做的是找到一个数的质因数的所有排列:这些就是它的因数。

我已经有一个模块来查找数字的主要功率因数,例如:

Main> primePowerFactors 196
[(2,2),(7,2)]

这基本上表明:2^2 * 7^2 == 196。从这里我想找到这些幂的所有排列,从而给出 196 的因数:

  • (2^0)(7^0) = 1
  • (2^1)(7^0) = 2
  • (2^2)(7^0) = 4
  • (2^0)(7^1) = 7
  • (2^1)(7^1) = 14
  • (2^2)(7^1) = 28
  • (2^0)(7^2) = 49
  • (2^1)(7^2) = 98

我想出了以下内容:

factors n = [a|a<-map facs (primePowerFactors n), y <- [0..(snd $ last $ primePowerFactors n)]]
 where 
  facs (x,y) = (x,y)   
rSq n = toInteger $ round $ sqrt (fromInteger n)    
psr n = last $ dropWhile (<= rSq n) $ factors n
p = foldl' (*) 1 $ takeWhile (< 190) primes
answer = (psr p) `mod` (10^16)

但我的问题是factors 不能正常工作。我希望它对每个素数因子的指数的所有可能值进行置换,然后找到给出该因子的乘积。如何修改它以返回 n 的因子?

【问题讨论】:

    标签: haskell factorization


    【解决方案1】:

    对于一些代码高尔夫,我编写了一个非常简单的很好的幂集函数。

    powerSet [] = []
    powerSet (x:xs) = xs : map (x:) (powerSet xs) ++ (powerSet xs)
    

    这个算法的一个缺陷是它不包括原始集合,但是这对你来说是完美的,因为它看起来不像你想要的那样。

    将此与将primePowerFactors n 转换为整数列表的方法相结合,比如说

    ppfToList = concatMap (\(x,y)->replicate y x)
    

    使用这些帮助器,生成来自数字 n 的因子列表

    factors n = nub . map product . powerSet . ppfToList . primePowerFactors $ n
    -- will be out of order, you can add a call to `sort` to fix that
    

    这种算法在列表理解方面可能更难表达。

    【讨论】:

    • 当你想要一个非常大的数的因数时,按顺序生成数的因数就变得很重要,否则使用 sort 将要求它在排序之前将每个单数存储在内存中,然后给我我的号码。因为我们知道 p 有 2^42 个因子,所以我们想要的因子应该在已排序的因子列表中的索引 2^42 -1 处。
    • 其实你不需要按照规范排序。您需要找到低于某个阈值的最大值。那只是maximum . filter (/= threshold),它是线性的,具有优化的恒定开销(无论如何都应该如此)。
    • 对不起maximum . filter (&lt;= threshold)
    【解决方案2】:

    首先facs是身份函数:

    facs (x,y) = (x,y)
    

    y 绑定在左侧的模式匹配中,而您可能希望它是列表理解中的 y。绑定在列表推导中的变量名称是该推导的本地变量,不能在不同的范围内使用,例如 where 子句。

    此外,列表推导中的y 仅根据最后一个因子指数计算:

    y <- [0..(snd $ last $ primePowerFactors n)]
    

    对于每个因子,都应该考虑它自己的指数,而不仅仅是最后一个因子的指数。

    一个更根本的问题是,factors 函数的返回类型似乎与它的意图不符:

    *Euler> :t factors
    factors :: Integer -> [(Integer, Int)]
    

    这会返回一个质因数幂的列表,同时它应该生成一个这些构造的列表,如下所示:

    [
       [(2,0), (7,0)],
       [(2,1), (7,0)],
       [(2,2), (7,0)],
       [(2,0), (7,1)],
       [(2,1), (7,1)],
       ...
    ]
    

    需要对所有可能的因子进行素因子分解,但该函数似乎只返回一个素因子分解。

    【讨论】:

    • 哦,我认为这是一个错误,应该是:facs (x,y) = (x^y) 这样factors 返回一个整数列表
    • 随着facs的改变,你永远不会产生像2^1*7^1这样的东西,而只会产生一个素数的幂。需要更改算法以产生不同主要因素的组合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    相关资源
    最近更新 更多