2009-10-13 80 views
0

对于Project Euler获得解决方案problem 2的最后一步,我有点卡住了。这是我到目前为止的来源。F中的项目欧拉问题2#

#light 
module pe2 (* Project Euler Problem 2 solution *) 

    open System 

    let Phi = 1.6180339887;; 

    let invPhi = 1.0/Phi;; 

    let rootOfFive = 2.236067977;; 

    let maxFib = 4000000.0; 

    let Fib n = 
    System.Math.Round((Phi**n - invPhi**n)/rootOfFive);; 

    let FibIndices = Seq.unfold(fun i -> Some(i, i+3.0)) 3.0;; 

    let FibNos = FibIndices |> Seq.map(fun index -> Fib(index));; 

    let setAllowedFibNos = FibNos |> Seq.filter(fun fn -> (fn <= maxFib));; 

// let answer = setAllowedFibNos |> Seq.fold (+) 0.0; 

当我取消注释最后一行时,过程似乎没有完成。所以我希望有人能给我一个正确的方向轻轻推动。我确实看过setAllowedFibNos,它看起来不错,但它也是一个无限序列,所以我只看到前三个术语。

另外,有人能指出我正确的方式来链各种序列在一起吗?我试过这样的事情:

let answer = Seq.unfold(fun i-> Some(i, i + 3.0)) 3.0 
|> Seq.map (fun index -> Fib(index)) 
|> Seq.filter(fun fn -> (fn <= maxFib)) 
|> Seq.fold (+) 0.0;; 

但是没有奏效。正如你大概猜测的那样,我只是在学习F#,所以请保持温和,如果之前已经提出并回答过这类问题,请发布一个链接到答案,我会撤回这一个。

回答

3

'setAllowedFibNos'的确是一个无限的seq计算; 'fold'需要整个序列,所以'过滤器'将永远运行,寻找另一个数字< = maxFib。

看看takeWhile:

http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Collections.Seq.html

我认为这是你想要的,而不是什么过滤器。

另请注意,您可以使用'sqrt 5.0'。

+4

此外,您还可以用它代替折Seq.sum和周围纤维蛋白原的匿名函数是多余的(Seq.map蛋白原就足够了)。 – dahlbyk 2009-10-14 00:17:53

+0

谢谢Brian。我对一件事很好奇 - 是不是Seq.filter使序列非无限? – 2009-10-14 00:23:07

+1

否;我可以过滤从1,2,3,4,...和even的结果仍然无限2,4,... – Brian 2009-10-14 00:50:43

0

我仍然试图习惯Seq方法。但是,没有它,我的解决方案就是这样。

 

#light 
let rec fib n = 
    match n with 
    |0|1 -> n 
    |_ -> fib(n-1) + fib(n-2) 

let maxFib = 4000000 
let phi = (1.0 + sqrt(5.0))/2.0 
let upperBound = 1 + int(log10((float(maxFib) - 0.5) * sqrt(5.0))/log10(phi)) 

[1..upperBound] |> List.filter (fun x-> x%3=0) |> List.map fib |> List.filter (fun x -> x%2 = 0) |> List.filter (fun x -> x List.sum |> printfn "%d" 
 
4
let rec Fib(n) = 
    if (n < 2) then 
     1 
    else 
     Fib(n-2) + Fib(n-1) 

Seq.initInfinite Fib 
|> Seq.takeWhile (fun a -> a <= 4000000) 
|> Seq.filter (fun a -> (a % 2) = 0) 
|> Seq.fold (+) 0 
0

我的解决办法是:

Seq.unfold (fun state -> 
    if (fst state + snd state > 4000000) then None 
    else Some(fst state + snd state, (snd state, fst state + snd state))) (0,1) 
|> Seq.filter (fun x -> x % 2 = 0) 
|> Seq.sum;; 
+1

将您的解决方案与[此片段]进行比较是有意义的(http://infsharpmajor.wordpress.com/2011/09/28/project-euler-problem-2/)。即使在这个玩具问题的大小上,它也会遵循构建泛型函数的更多[FP-idiomatic方法](http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf),然后通过使用组合器来获得具体结果。在这个“粘合函数在一起”的方式之后,你不应该把终止条件嵌入到'Seq.unfold'生成器函数中,而是应该延迟序列无限期地评估到特定的'4000000'需求。 – 2012-06-22 17:42:43