Problem 32 - 積の組合せ
ぜぃぜい。やっと解けた。
39 × 186 = 7254のように1から9が一回づつ現われる積の組合せを見つける。
積の組合せは
- 1桁 * 4桁 = 4桁
- 2桁 * 3桁 = 4桁
しかない。
ということで、
- 1〜9の中から、1桁or2桁の順列を求める。
- 差集合を取って、4桁or3桁の順列を求める。
- 掛け算して、残りと比べる。
- 重複が出るっぽいのでunique (和集合でよさげ)
やることはシンプルなんだけど、やたらなげぇ。
(define (unique list) (fold-right (lambda (a b) (if (member a b) b (cons a b))) '() list)) (define (list->number l) (letrec ((iter (lambda (l cont) (if (null? l) (cont 0 0) (iter (cdr l) (lambda (sum k) (cont (+ (* (car l) (expt 10 k)) sum) (+ k 1)))))))) (iter l (lambda (sum k) sum)))) (define (number->list n . base) (letrec ((b (if (null? base) 10 (car base))) (iter (lambda (acc n) (let ((q (quotient n b)) (m (cons (modulo n b) acc))) (if (zero? q) m (iter m q)))))) (iter '() n))) (define (permutations s . m) (letrec ((flatmap (lambda (proc s) (apply append (map proc s)))) (remove-1 (lambda (item s) (cond ((null? s) '()) ((equal? (car s) item) (cdr s)) (else (cons (car s) (remove-1 item (cdr s))))))) (iter (lambda (s m) (if (or (zero? m) (null? s)) (list '()) (flatmap (lambda (l) (map (lambda (p) (cons l p)) (permutations (remove-1 l s) (- m 1)))) s))))) (iter s (if (null? m) (length s) (car m))))) (define (problem32) (letrec ((diff (lambda (a b) (lset-difference = a b))) (seed (iota 9 1)) (iter (lambda (n) (if (= n 3) '() (append (fold (lambda (l acc) (let* ((d (diff seed l)) (p (permutations d (- 5 n)))) (append (fold (lambda (x acd) (let* ((res (* (list->number l) (list->number x))) (res-l (number->list res)) (diff-dx (diff d x))) (if (and (= (length diff-dx) (length res-l)) (null? (diff diff-dx res-l))) (cons res acd) acd))) '() p) acc))) '() (permutations seed n)) (iter (+ n 1))))))) (apply + (unique (iter 1)))))
もうちょっと短く書きたいところ・・・。