Problem 21 » 履歴 » バージョン 2
Noppi, 2024/01/04 05:38
| 1 | 1 | Noppi | [ホーム](https://redmine.noppi.jp) - [[Wiki|Project Euler]] |
|---|---|---|---|
| 2 | # [[Problem 21]] |
||
| 3 | |||
| 4 | ## Amicable Numbers |
||
| 5 | Let $d(n)$ be defined as the sum of proper divisors of $n$ (numbers less than $n$ which divide evenly into $n$). |
||
| 6 | If $d(a) = b$ and $d(b) = a$, where $a \ne b$, then $a$ and $b$ are an amicable pair and each of $a$ and $b$ are called amicable numbers. |
||
| 7 | For example, the proper divisors of $220$ are $1, 2, 4, 5, 10, 11, 20, 22, 44, 55$ and $110$; therefore $d(220) = 284$. The proper divisors of $284$ are $1, 2, 4, 71$ and $142$; so $d(284) = 220$. |
||
| 8 | Evaluate the sum of all the amicable numbers under $10000$. |
||
| 9 | |||
| 10 | ## 友愛数 |
||
| 11 | d(n) を n の真の約数の和と定義する. (真の約数とは n 以外の約数のことである. ) |
||
| 12 | もし, d(a) = b かつ d(b) = a (a ≠ b のとき) を満たすとき, a と b は友愛数(親和数)であるという. |
||
| 13 | |||
| 14 | 例えば, 220 の約数は 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 なので d(220) = 284 である. |
||
| 15 | また, 284 の約数は 1, 2, 4, 71, 142 なので d(284) = 220 である. |
||
| 16 | |||
| 17 | それでは10000未満の友愛数の和を求めよ. |
||
| 18 | |||
| 19 | ```scheme |
||
| 20 | 2 | Noppi | (import (scheme base) |
| 21 | (gauche base) |
||
| 22 | (math prime) |
||
| 23 | (scheme list) |
||
| 24 | (scheme vector)) |
||
| 25 | |||
| 26 | (define (non-primes num) |
||
| 27 | (let ([primes-num (take-while (^n (<= n num)) (primes))] |
||
| 28 | [iota-4-num (iota (+ num 1 -4) 4)]) |
||
| 29 | (lset-difference = iota-4-num primes-num))) |
||
| 30 | |||
| 31 | (define (proper-divisors num) |
||
| 32 | (let loop ([n 2] [result '()]) |
||
| 33 | (cond |
||
| 34 | [(< num (* n n)) (delete-duplicates (cons 1 result))] |
||
| 35 | [(zero? (mod num n)) |
||
| 36 | (loop (+ n 1) (cons* n (div num n) result))] |
||
| 37 | [else (loop (+ n 1) result)]))) |
||
| 38 | |||
| 39 | (define (sum-divisors lis) |
||
| 40 | (map |
||
| 41 | (^n (cons n |
||
| 42 | (apply + (proper-divisors n)))) |
||
| 43 | lis)) |
||
| 44 | |||
| 45 | (define (amicable-numbers num) |
||
| 46 | (let ([divisors-list (sum-divisors (non-primes num))] |
||
| 47 | [table (make-vector (+ num 1) #f)]) |
||
| 48 | (for-each |
||
| 49 | (^[cell] |
||
| 50 | (let ([a (car cell)] |
||
| 51 | [b (cdr cell)]) |
||
| 52 | (when (and (not (= a b)) (<= b num)) |
||
| 53 | (set! (vector-ref table a) b)))) |
||
| 54 | divisors-list) |
||
| 55 | (vector-fold |
||
| 56 | (^[lis index num-or-f] |
||
| 57 | (cond |
||
| 58 | [(not num-or-f) lis] |
||
| 59 | [(not (vector-ref table num-or-f)) lis] |
||
| 60 | [(= index (vector-ref table num-or-f)) |
||
| 61 | (set! (vector-ref table index) #f) |
||
| 62 | (set! (vector-ref table num-or-f) #f) |
||
| 63 | (cons* index num-or-f lis)] |
||
| 64 | [else lis])) |
||
| 65 | '() |
||
| 66 | (list->vector (iota (+ num 1))) |
||
| 67 | table))) |
||
| 68 | |||
| 69 | (define answer-21 |
||
| 70 | (apply + (amicable-numbers 9999))) |
||
| 71 | |||
| 72 | (format #t "21: ~d~%" answer-21) |
||
| 73 | 1 | Noppi | ``` |