我正在项目Euler做problem 61并提出以下代码(以测试他们提供的案例):
p3 n = n*(n+1) `div` 2
p4 n = n*n
p5 n = n*(3*n -1) `div` 2
p6 n = n*(2*n -1)
p7 n = n*(5*n -3) `div` 2
p8 n = n*(3*n -2)
x n = take 2 $ show n
x2 n = reverse $ take 2 $ reverse $ show n
pX p = dropWhile (< 999) $ takeWhile (< 10000) [p n|n<-[1..]]
isCyclic2 (a,b,c) = x2 b == x c && x2 c == x a && x2 a == x b
ns2 = [(a,b,c)|a <- pX p3 , b <- pX p4 , c <- pX p5 , isCyclic2 (a,b,c)]
并且所有ns2
都返回一个空列表,但cyclic2
以问题中给出的参数为例,但系列没有出现在解决方案中。问题必须在列表理解ns2
中,但我看不出哪里,我做错了什么?
另外,我怎样才能使pX
只获得pX (n)
以前pX
中使用的pX?
isCyclic (a,b,c,d,e,f) = x2 a == x b && x2 b == x c && x2 c == x d && x2 d == x e && x2 e == x f && x2 f == x a
ns = [[a,b,c,d,e,f]|a <- pX p3 , b <- pX p4 , c <- pX p5 , d <- pX p6 , e <- pX p7 , f <- pX p8 ,isCyclic (a,b,c,d,e,f)]
answer = sum $ head ns
答案 0 :(得分:2)
订单很重要。问题中的循环数是8128,2882,8281,这些不是P3 / 127,P4 / 91,P5 / 44,而是P3 / 127,P5 / 44,P4 / 91.
您的代码只检查订单8128,8281,2882,这不是循环的。
如果你检查
,你会得到结果isCyclic2 (a,c,b)
列表理解。
答案 1 :(得分:2)
编辑:错误的问题! 我以为你在谈论循环号码问题,抱歉!
使用这样的方法有一种更有效的方法:
take (2 * l x -1) . cycle $ show x
where l = length . show
试一试,看看它在哪里。
答案 2 :(得分:1)
如果我在这里理解你,你就不再问为什么你的代码不起作用,而是如何让它更快。这实际上是Project Euler寻找解决问题的有效方法的全部乐趣,因此请小心谨慎,首先考虑自己减少搜索空间。我建议你让Haskell打印出三个列表pX p3,pX p4,pX p5,看看你是如何寻找一个循环的。
如果你按照你的列表理解继续进行,你将从每个列表的第一个元素开始,1035,1024,1080。我很确定你会在选择1035和1024之后立即停止并且不测试周期来自P5的任何值,更不用说尝试涉及这两个数字的组合的所有排列。
(我还没有真正研究过这个问题,所以这就是我要加速它的方法。可能会有一些数学魔法甚至更快)
首先,开始查看从pX获得的数字。你可以放弃更多。例如,P3包含6105 - 您无法在以“05”开头的其他集合中找到数字。因此,您也可以删除模数为100的数字小于10的数字。
然后(对于3组的情况),我们有时可以看到在绘制两个数字之后,在最后一组中不能有任何数字会给你一个循环,无论你如何排列(例如来自P3的1035)来自P4的3136 - 这里不能有一个循环。)
我可能会尝试通过从一个列表中的元素开始逐个构建链,并且对于每个元素,从剩余的列表中找到有效后继元素。对于那些你找到的人,继续尝试从剩余的列表中找到下一个链元素。当您使用每个列表中的一个数字构建链时,您只需检查最后一个数字的最后两位是否与第一个数字的前两位相匹配。
注意在寻找后继者时,您再次不必遍历整个列表。例如,如果您正在寻找P5的3015继任者,那么当您达到1600或更大的数字时,您可以停止。
如果仍然太慢,您可以将除第一个之外的列表转换为映射,其中映射键是前两个数字,相关值是以这些数字开头的数字列表。使您免于一次又一次地从列表中查看列表。
我希望这有点帮助。
答案 3 :(得分:0)
您可以将[p3, p4, p5, p6, p7, p8]
个函数统一到一个函数中,该函数将3
中的p3
作为参数等。
要查找模式是什么,您可以以
的形式创建所有函数pX n = ... `div` 2