Problem 38 - Pandigital数

後で読み返してみたら、案外簡単だったり。

Problem 38 - PukiWiki

組合せ数が多いかと思ってたけど、そうでもなかった。

1のだけの組合せは無い。と書いてあったのでほっと一安心。回答が9876...になっちゃうのでありえないか。


安心したところで範囲を考える。

12345 24680となることは無いので、最大4桁まで見ればいい。1万 * 9回検索すればなんとかなるようだ。


後はガンガン連結。もちろん総当り検索。

(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 (problem38 n)
  (letrec ((cmp (iota n 1))
           (pandigital? (lambda (l) (and (= (length l) n)
                                         (null? (lset-difference = cmp l)))))
           (search
             (lambda (m i acc)
               (let ((a (append acc (number->list (* m i)))))
                 (cond ((> (length a) n) #f)
                       ((pandigital? a) (list->number a))
                       (else
                         (search m (+ i 1) a))))))
           (iter
             (lambda (m acc)
               (if (= m 10000)
                   acc
                   (let ((res (search m 1 '())))
                     (iter (+ m 1) (if res (max res acc) acc)))))))

    (iter 1 0)))

(problem38 9) ; 932718654

ちと若い番号を攻めようかな。