在Haskell中实现分解方法

时间:2009-12-06 14:41:40

标签: haskell factorization

我正在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 的因素?

2 个答案:

答案 0 :(得分:2)

对于某些代码高尔夫我写了一个很简单的功能集功能。

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

根据列表理解,这种算法可能有点难以表达。

答案 1 :(得分:1)

首先,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)],
   ...
]

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