PageRenderTime 22ms CodeModel.GetById 9ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/extra/project-euler/043/043.factor

http://github.com/abeaumont/factor
Unknown | 101 lines | 73 code | 28 blank | 0 comment | 0 complexity | 47529c9f07e6b03aa5a4bd62ccf80e1a MD5 | raw file
  1! Copyright (c) 2008 Aaron Schaefer.
  2! See http://factorcode.org/license.txt for BSD license.
  3USING: combinators.short-circuit kernel math math.functions math.combinatorics
  4    math.parser math.ranges project-euler.common sequences sets sorting ;
  5IN: project-euler.043
  6
  7! http://projecteuler.net/index.php?section=problems&id=43
  8
  9! DESCRIPTION
 10! -----------
 11
 12! The number, 1406357289, is a 0 to 9 pandigital number because it is made up
 13! of each of the digits 0 to 9 in some order, but it also has a rather
 14! interesting sub-string divisibility property.
 15
 16! Let d1 be the 1st digit, d2 be the 2nd digit, and so on. In this way, we note
 17! the following:
 18
 19!     * d2d3d4  = 406 is divisible by 2
 20!     * d3d4d5  = 063 is divisible by 3
 21!     * d4d5d6  = 635 is divisible by 5
 22!     * d5d6d7  = 357 is divisible by 7
 23!     * d6d7d8  = 572 is divisible by 11
 24!     * d7d8d9  = 728 is divisible by 13
 25!     * d8d9d10 = 289 is divisible by 17
 26
 27! Find the sum of all 0 to 9 pandigital numbers with this property.
 28
 29
 30! SOLUTION
 31! --------
 32
 33! Brute force generating all the pandigitals then checking 3-digit divisiblity
 34! properties...this is very slow!
 35
 36<PRIVATE
 37
 38: subseq-divisible? ( n index seq -- ? )
 39    [ 1 - dup 3 + ] dip subseq 10 digits>integer swap divisor? ;
 40
 41: interesting? ( seq -- ? )
 42    {
 43        [ [ 17 8 ] dip subseq-divisible? ]
 44        [ [ 13 7 ] dip subseq-divisible? ]
 45        [ [ 11 6 ] dip subseq-divisible? ]
 46        [ [ 7  5 ] dip subseq-divisible? ]
 47        [ [ 5  4 ] dip subseq-divisible? ]
 48        [ [ 3  3 ] dip subseq-divisible? ]
 49        [ [ 2  2 ] dip subseq-divisible? ]
 50    } 1&& ;
 51
 52PRIVATE>
 53
 54: euler043 ( -- answer )
 55    1234567890 number>digits 0 [
 56        dup interesting? [
 57            10 digits>integer +
 58        ] [ drop ] if
 59    ] reduce-permutations ;
 60
 61! [ euler043 ] time
 62! 60280 ms run / 59 ms GC time
 63
 64
 65! ALTERNATE SOLUTIONS
 66! -------------------
 67
 68! Build the number from right to left, generating the next 3-digits according
 69! to the divisiblity rules and combining them with the previous digits if they
 70! overlap and still have all unique digits. When done with that, add whatever
 71! missing digit is needed to make the number pandigital.
 72
 73<PRIVATE
 74
 75: candidates ( n -- seq )
 76    1000 over <range> [ number>digits 3 0 pad-head ] map [ all-unique? ] filter ;
 77
 78: overlap? ( seq -- ? )
 79    [ first 2 tail* ] [ second 2 head ] bi = ;
 80
 81: clean ( seq -- seq )
 82    [ unclip 1 head prefix concat ] map [ all-unique? ] filter ;
 83
 84: add-missing-digit ( seq -- seq )
 85    dup natural-sort 10 iota swap diff prepend ;
 86
 87: interesting-pandigitals ( -- seq )
 88    17 candidates { 13 11 7 5 3 2 } [
 89        candidates swap cartesian-product concat
 90        [ overlap? ] filter clean
 91    ] each [ add-missing-digit ] map ;
 92
 93PRIVATE>
 94
 95: euler043a ( -- answer )
 96    interesting-pandigitals [ 10 digits>integer ] map-sum ;
 97
 98! [ euler043a ] 100 ave-time
 99! 10 ms ave run time - 1.37 SD (100 trials)
100
101SOLUTION: euler043a