Problem 122 解けたよ。
どもです。
さっき地震があったので思い出したのですが,
3月12日に大きい地震が来ると予想している whitypig さんです。
根拠?
オレが地震だった,3月12日か,もしくは,3月10日を狙うだろうから。
この日記にはまだ書いてなかったので書いておこっと。
defstruct でハマッてた。
時間はかかるは,メモリを喰うはで大変でしたが,なんとか。
power-tree っぽいのを作る build-power-tree と,
その木をトラバースする traverse-pt にわけないで,
一回で計算すればたぶんだいぶ速くなると予想。
(defun euler-problem-122-2 () (reduce #'+ (coerce (subseq (traverse-pt (build-power-tree 11) (make-array (list 201) :initial-element nil) 0) 1) 'list))) (euler-problem-122-2) ;; (EULER-PROBLEM-122-2) took 35,157 milliseconds (35.157 seconds) to run ;; with 4 available CPU cores. ;; During that period, 34,219 milliseconds (34.219 seconds) were spent in user mode ;; 406 milliseconds (0.406 seconds) were spent in system mode ;; 30,360 milliseconds (30.360 seconds) was spent in GC. ;; 1,086,319,592 bytes of memory allocated.
最初,自分で考えて適当な関数をつくって,解いてみたが,
間違っていた。
しばらく考えて無理そうなので,ググった。
んで,power tree なるものの存在を知った。
で,重複を許した power tree を作ってみようと,
ノードを表す構造体として,
(defstruct pt-node (value 0 :type fixnum) (children nil :type list) (parent nil))
としたんです。
んで,作って色々したら,stack overflow condition とかいうエラーが出る。
理由がわからん。
ググってみるも,stackoverflow.com ばっかりひっかかって大変。
んでなんとなーくという理由で「lisp tree parent circular」とかで検索して,
やっと理由がわかった。
http://www.wutka.com/download/fibheap.lisp
から引用させてもらいます。
;; Need a special print function. The default print function goes ;; berzerk with the circular list (defun print-fib-heap-node (n stream depth) (when (< depth 20) (if (null n) (print "NIL") (progn (dotimes (d depth) (format stream " ")) (format stream "fib-heap-node(~a)~%" (fib-heap-node-data n)) (map-fib-heap-node-list #'(lambda (x) (print-fib-heap-node x stream (+ depth 1))) (fib-heap-node-child n))))))
デフォルトの print function で循環リストを出力しようとすると,
ベルセルクって,ガッツになって,暴走して,シールケたんはぁはぁ状態になって,
そうこうしているうちに,某映画版が黒歴史になってゴッドに愛されるとか,
そういう風にベルセルクるので,自前の print function を用意しようと
いうことですね。あい。
ちなみに,ワタシは映画版を見てないし,興味ないし,見る予定もないです。
あい。
で,下記のように変更して解決。
(defstruct (pt-node (:print-function print-pt-node)) (value 0 :type fixnum) (children nil :type list) (parent nil)) (defun print-pt-node (node stream depth) (when (< depth 20) (if (null node) (format stream "NIL") (progn (format stream (make-string depth :initial-element #\ )) (format stream "PT-NODE(~A): " (pt-node-value node)) (if (pt-node-children node) (loop for n in (pt-node-children node) do (format stream "~A " (pt-node-value n))) (format stream "NIL")) (terpri stream) (mapc (lambda (n) (print-pt-node n stream (1+ depth))) (pt-node-children node))))))
子を表示しようとする。
parent スロットを表示しようとする。
その parent スロットの children スロットを表示しようとする。
で,その children のうちの1つのノードの parent を表示しようとする。
以下繰り返し,あーんど,スタックオーバーフロー。
なるほどね。
親と子の両方を持つときには,print function を自前で用意しましょうということですね。
あい。