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

http://github.com/abeaumont/factor · Factor · 101 lines · 41 code · 28 blank · 32 comment · 6 complexity · 47529c9f07e6b03aa5a4bd62ccf80e1a MD5 · raw file

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