Claudio Cherubino (from fsharp.it/) posted his solution to Euler Project – problem 53. As I dealed a lot with Dynamic Programming in the recent time, I tried to solve the problem with a dynamic program in F#.
How many values of C(n,k), for 1 ≤ n ≤ 100, exceed one-million?
Remark: C(n,k) are the binomial coefficients.
As it turned out, this is not that complicated if one knows the recursive function for the binomial coefficients (see Wikipedia):
with
This is easily transformed into a F# program:
let binomials = Array2.create 101 101 1I let answer = ref 0 for n in [1..100] do for k in [1..n - 1] do binomials.[n, k] <- binomials.[n - 1,k] + binomials.[n - 1,k - 1] if binomials.[n, k] > 1000000I then answer := !answer + 1 !answer |> printf "Answer: %A"
Claudio’s program took 1315ms on my computer. The dynamic program needs only 63ms. But we can still do better if we use the symmetry of Pascal’s triangle.
This leads to an algorithm, which calculates only half of the binomial coefficients.
let binomials = Array2.create 101 101 1I let answer = ref 0 for n in [1..100] do for k in [1..n/2] do let b = binomials.[n - 1,k] + binomials.[n - 1,k - 1] binomials.[n, k] <- b binomials.[n, n - k] <- b if b > 1000000I then if k = n-k then answer := !answer + 1 else answer := !answer + 2
!answer |> printf "Answer: %A"
This version needs only 45ms – but we are not ready. I mentioned Pascal’s triangle and its symmetry. But we can use another property. We don’t have to calculate the complete row, if we exceed 100000. All values behind this threshold have to be greater.
let binomials = Array2.create 101 101 1I let answer = ref 0 for n in [1..100] do let threshold_reached = ref false let c = ref 0 for k in [1..n/2] do if not !threshold_reached then let b = binomials.[n - 1,k] + binomials.[n - 1,k - 1] binomials.[n, k] <- b binomials.[n, n - k] <- b if b > 1000000I then threshold_reached := true else c := !c + 1 if !threshold_reached then answer := !answer + (n - 1) - (2 * !c)
!answer |> printf "Answer: %A"
This final version took only 29 ms.
In the next posting I will show a version using memoization.
Tags: binomial coefficient, dynamic program, F#, problem 53, project euler