プロジェクトオイラー28問目

プロジェクトオイラー28問目

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13

という5×5のスパイラルがあったとき、[1]、[3 5 7 9]、[13 17 21 25]という各サイズの正方形の角にある数字の合計は101。では、1001×1001のスパイラルのときの合計は。

Clojureで書いてみる。

(defn corner-total [n]
     (let [max (* n n)
	   diff (- n 1)]
       (if (not (== n 1))
	 (- (* max 4)
	    (* diff (+ 1 2 3)))
	 1)))

(defn total [n]
  (reduce + 
	  (map corner-total (range 1 (+ n 1) 2))))

(println
 (total 1001))

再帰っぽく。

(defn corner-seq [seq n]
  (let [start (* n n)
	diff (- n 1)]
    (if (== n 1)
      (cons 1 seq)
      (recur
       (concat (range (- start (* diff 3)) (+ start 1) diff) seq)
       (- n 2)))))
  
(defn e28 [n]
  (println
   (corner-seq () n))
  (println
   (reduce + (corner-seq () n))))

(e28 1001)

シーケンスって何だ。よくわからん。

TCO再帰の呼び出しのところをrecurと明示的に書き直すだけでいいらしい。この例だと10万ぐらいの値を渡すとスタックオーバーフローを起こすけど、corner-seqをrecurにすると落ちなくなる。