p095.scm 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. (define-module (solved p095))
  2. (use-modules (euler math))
  3. ;;; Easiest way to do this: 1->n loop, continue until we get a chain or a value goes above 1 mil
  4. ;;; Let's not worry about a cache in case it's not needed.
  5. ;;; Why don't we do a quick test...
  6. ;;; If we don't use it: it takes o(n^2) to find divisors
  7. ;;; o(n^3) to loop through each value
  8. ;;; A cache is only helping us with a constant time amount of recalculation...
  9. ;;; In conclusion, it's probably not useful to use a cache.
  10. ;;; Testing time to find the divisors of a million values
  11. ;;; Okay this is too slow, so we need a better way of finding divisors...
  12. ;;; Would it make sense to compute all the divisors first, and then do the computation?
  13. ;;; That would help separate concerns for sure....o
  14. (define (proper-div-sum divisors)
  15. (apply + divisors))
  16. ;; Will simply loop through all the proper divisors and get the chain
  17. (define (find-largest-amicable-chain limit)
  18. (define proper-div-lst (proper-divisors-in-range limit))
  19. ;; I wonder which loop looks better: doing let beforehand or doing let in the loop...
  20. (define (get-chain start)
  21. (let lp ([curr-val start] [chain (list start)])
  22. (let ([next-val
  23. (proper-div-sum (array-ref proper-div-lst curr-val))])
  24. (cond
  25. [(> next-val limit) '()]
  26. [(= start next-val) chain]
  27. [(memq next-val chain) '()]
  28. [else (lp next-val
  29. (cons next-val chain))]))))
  30. (let lp ([i 1] [max-chain '()])
  31. (if (> i limit) max-chain
  32. (lp (1+ i)
  33. (let ([curr-chain (get-chain i)])
  34. (if (> (length curr-chain)
  35. (length max-chain))
  36. curr-chain
  37. max-chain))))))
  38. (define (proc x) (1+ x))