Project Euler Problem #74!

March 26th, 2010
by Serinox

Problem #74 says:

The number 145 is well known for the property that the sum of the factorial of its digits is equal to 145:

1! + 4! + 5! = 1 + 24 + 120 = 145

Perhaps less well known is 169, in that it produces the longest chain of numbers that link back to 169; it turns out that there are only three such loops that exist:

169 → 363601 → 1454 → 169
871 → 45361 → 871
872 → 45362 → 872

It is not difficult to prove that EVERY starting number will eventually get stuck in a loop. For example,

69 → 363600 → 1454 → 169 → 363601 (→ 1454)
78 → 45360 → 871 → 45361 (→ 871)
540 → 145 (→ 145)

Starting with 69 produces a chain of five non-repeating terms, but the longest non-repeating chain with a starting number below one million is sixty terms.

How many chains, with a starting number below one million, contain exactly sixty non-repeating terms?

This solution is done with brute force by checking the chain length and counting the matching results. Could be made a lot faster if a collection of previous results was stored to avoid duplicating work. But it runs fast enough for me.

Solution in F# and requires .Net 4 and the FSharp powerpack.

#light

open System
open System.Diagnostics
open Microsoft.FSharp.Linq
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Math
open System.Numerics

let rec Factorial (x:int64) =
    if x <= (int64 1) then
        (int64 1)
    else
        x * Factorial (x-(int64 1))

let DigitalSumFactorial (x:int64) =
    x.ToString().ToCharArray()
    |> Seq.map (fun (x:char) -> Int64.Parse (x.ToString()))
    |> Seq.map Factorial
    |> Seq.sum

let rec CheckChain (x:int64) (k:List<int64>) =
    if List.contains x k then
        k.Length
    else
        let nK = x :: k
        let nX = DigitalSumFactorial x
        CheckChain (nX) (nK)

type TestCase (y:int64) =
    let Chainl = CheckChain y List.empty
    member x.Length
        with get() = Chainl

let watch = new Stopwatch()
watch.Start()

let Answer =
    [(int64 2) .. (int64 999999)]
    |> PSeq.map (fun (x:int64) -> TestCase(x))
    |> PSeq.filter (fun (x:TestCase) -> if x.Length = 60 then true else false)
    |> PSeq.length

Console.WriteLine(Answer)
watch.Stop()
Console.WriteLine(watch.Elapsed)
Console.ReadKey() |> ignore

Tags: , , ,
Posted in Project Euler | Comments (0)

No comments yet

Leave a Reply

You must be logged in to post a comment.