有没有办法在Haskell中优化这个程序?

时间:2009-10-01 06:00:24

标签: haskell math optimization

我在做项目euler question 224。并且在Haskell中掀起了这个列表理解:

prob39 = length [ d | d <- [1..75000000], c <- [1..37500000], b <-[1..c], a <- [1..b], a+b+c == d, a^2 + b^2 == (c^2 -1)]

我用GHC编译它并且它已经以超过一个小时的平均内核优先级运行而没有返回结果。我该怎么做才能优化此解决方案?我似乎越来越善于以天真的方式找到蛮力解决方案。我能做些什么吗?

编辑:我也不清楚'整数长度'的定义,这是否意味着边长的大小落在正整数集中,即:1,2,3,4,5 .. 。?

2 个答案:

答案 0 :(得分:8)

我的Haskell并不令人惊讶,但我认为这将是n ^ 5。

看起来你要说的是每个n从1到7千5百万,用一个小于或等于75百万的perimiter检查每个“几乎钝的”三角形,看它是否有perimiter n。

另外,我不确定列表推导是否足够聪明,一旦c ^ 2 -1的当前值大于a ^ 2 + b ^ 2就停止查看。

一个简单的重构应该是

prob39 = length [ (a, b, c) | c <- [1..37500000], b <-[1..c], a <- [1..b], a^2 + b^2 == (c^2 -1), (a + b + c) <= 75000000]

你可以做得更好,但这应该快7500万倍。

对这种重构不太确定,但它也应该大大加快速度:

prob39 = length [ (a, b, c) | a <- [1..25000000], b <-[a..(75000000 - 2*a)], c <- [b..(75000000 - a - b)], a^2 + b^2 == (c^2 -1)]

语法可能不是100%。该想法是a只能是1到2,500万(因为a&lt; = b&lt; = c和a + b + c <= 7500万)。 b只能介于一半到七千万之间(因为b <= c)而c只能从b到75百万 - (a + b),否则周长将超过7500万。

编辑:更新的代码段,其中有几个错误。

另一个快速建议,你可以用c&lt; - [b..min((75000000 - a - b))的行代替c&lt; - [b ..(75000000 - a - b)], sqrt(a a + b b)+ 1)]。没有必要费心检查c的任何大于(a ^ 2 + b ^ 2)的平方根的上限的值。不记得那些是否是haskell中正确的min / sqrt函数名称。

在这个问题上获得OCD,我还有一些建议。

1)你可以将b的上限设置为当前上限的min和^ 2 * 2 + 1.这是基于(x + 1)^ 2 - x ^ 2 =的原理2x + 1.b不能比我们可以保证的那样大得多(a ^ 2)+(b ^ 2)&lt; (B + 1)^ 2。

2)将c的下限设置为b + 1和floor的最大值(sqrt(a ^ 2 + b ^ 2)-1)。就像C的上限一样,不需要测试不可能正确的值。

答案 1 :(得分:0)

附带@patros给出的建议。 我想分享我对这个问题的看法。

如果我们在某个周长(例如100000)上打印a,b和c的值,则可以观察到a和b始终取偶数,而c始终取奇数。因此,如果我们使用这些限制来优化代码,则可以跳过几乎一半的检查。