[Small-cl-src] nines.lisp
Luke Gorrie
luke at bluetail.com
Fri May 14 13:48:41 UTC 2004
;;; nines.lisp --- Program to solve the "Nine Nines" problem.
;;; Spec at http://www.itasoftware.com/careers/programmers-archive.php
;;; Written by Luke Gorrie <luke at bluetail.com> on April 26, 2002.
;;; Hacked by Darius Bacon <darius at accesscom.com> to fit on one screen.
;; The possible results of an expression containing one nine are just
;; 9 and -9. Any expression with N (> 1) nines can be seen as a
;; combination of two smaller subexpressions by some operator,
;; resulting in any combination of the subexpressions' possible
;; results. The full solution for nine nines is constructed
;; efficiently from smaller results using dynamic programming.
;;
;; Note: Because unary minus can be applied at any time (including the
;; very end), the internal representation only explicitly deals with
;; absolute values, which are understood to be +/-.
(defvar *solutions* nil
"Array of sets of possible absolute values for <index>-nine expressions.")
(defun run (n)
"Return the solution to the N Nines problem."
(let ((*solutions* (make-array (1+ n) :initial-element nil)))
(setf (aref *solutions* 1) '(9))
(loop for k from 2 to n
do (setf (aref *solutions* k) (solve k)))
(find-missing (aref *solutions* n))))
(defun solve (n)
"Calculate the possible values for an expression of N nines."
(let ((table (make-hash-table :test 'eql)))
(do ((x (1- n) (1- x))
(y 1 (1+ y)))
((> y x) (hash-table-keys table))
(add-combinations table x y))))
(defun add-combinations (table i j)
"Add to TABLE the absolute values that can result from combining expressions
of I nines and J nines using any operator, with either on the left hand side."
(labels ((add-answer (x) (setf (gethash x table) t)))
(dolist (x (aref *solutions* i))
(dolist (y (aref *solutions* j))
(add-answer (+ x y))
(add-answer (abs (- x y)))
(add-answer (* x y))
(unless (zerop y) (add-answer (/ x y)))
(unless (zerop x) (add-answer (/ y x)))))))
(defun find-missing (list)
"Find the first 'missing' integer in the (sorted) LIST, starting from 0."
(loop for x in (sort (remove-if-not #'integerp list) #'<)
for n from 0
when (/= x n) return n))
(defun hash-table-keys (hashtable)
"Return a list of the keys of HASHTABLE."
(let ((keys '()))
(maphash (lambda (key value) (push key keys))
hashtable)
keys))
More information about the Small-cl-src
mailing list