這些評論意味着你真正需要的是更好的算法。
但是,讓我們嘗試不同的東西,看看我們可以對當前代碼什麼的優化:
let rightTrianglesCubic p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a + b + c == p]
首先,請注意我們如何遍歷的[1..b]
所有的值,直到我們找到一個地方a + b + c == p
。但是,在保存的唯一價值是a = p - b - c
,所以我們完全可以跳過循環,並製作成二次算法如下:
let rightTrianglesQuadraticA p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], let a = p - b - c, a^2 + b^2 == c^2]
有一個小問題,這種方法:
λ rightTrianglesCubic 120
[(30,40,50),(24,45,51),(20,48,52)]
λ rightTrianglesQuadraticA 120
[(40,30,50),(30,40,50),(45,24,51),(24,45,51),(48,20,52),(20,48,52),(0,60,60)]
我們得到一些額外的結果!這是因爲我們忽略了a <- [1..b]
所做的隱含條件,即1 <= a
和a <= b
。因此,讓我們添加這些回
let rightTrianglesQuadraticB p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], let a = p - b - c, a^2 + b^2 == c^2, 1 <= a, a <= b]
而現在我們得到正確的答案:
λ rightTrianglesQuadraticB 120
[(30,40,50),(24,45,51),(20,48,52)]
由於b
每個值都有一個唯一的a
,條件1 <= a
和a <= b
可以表述爲條件在b
。 1 <= a
與1 <= p - b - c
或 b <= p - c - 1
相同。 a <= b
與p - b - c <= b
或p - c <= 2*b
或 div (p - c + 1) 2 <= b
相同。
這讓我們縮小環路b <- [1..c]
界限:
let rightTrianglesQuadraticC p = [ (a,b,c) | c <- [1..quot p 2], b <- [max 1 (div (p - c + 1) 2) .. min c (p - c - 1) ], let a = p - b - c, a^2 + b^2 == c^2]
我們甚至可以通過提的是,爲了a < b < c
與a+b+c == p
,我們必須收縮對c <- [1..quot p 2]
邊界c > p/3
:
let rightTrianglesQuadraticD p = [ (a,b,c) | c <- [1 + quot p 3..quot p 2], b <- [max 1 (div (p - c + 1) 2) .. min c (p - c - 1) ], let a = p - b - c, a^2 + b^2 == c^2]
這是關於優化這個特定的代碼可以去。爲了進一步提高性能,我們需要完全切換算法。
我認爲一般的想法是使用不同的算法,即不是蠻力。這並不是列表理解錯誤,這是一個嵌套for循環的蠻力算法的典型例子。這個算法的複雜性在'O(n^3)'周圍,隨着'n'變大,複雜度不是很高。 – bheklilr
對,這是一個算法/數學問題,而不是Haskell /性能問題。你對解決這個尋找具有規定邊界的直角三角形問題有多大興趣?有效的方法是使用畢達哥拉斯三元組的參數化,並通過分解「p」開始...... –
@ReidBarton:是的,好點,部分回答了這個問題:約束不適用於域規範。例如,對於'c < - [1 ...(p2)]','b < - [1..c]'和'a < - [1]的所有值'(a,b,c) ..b]'將被檢查,然後*然後*然後約束被應用(相反,也就是說,將'a'限制爲等於'pcb'的值。這是我詢問的Haskell-y問題。 – orome