8×8の盤に, 5個のクイーンを, 盤のすべての場所を支配するように置く という問題である. 1863年の本にあるそうだから, 古典的問題である.
この解は, 4860通りあるらしいので, 自分でも計算することにした.
私のことだから, Schemeを使う. またSchemeを使うなら, bit-stringが役立つ.
プログラムを書いたら, 思ったより簡単で, 1時間はかからなかった. こんな具合だ.
(define (r n) (map (lambda (i) (+ (* n 8) i)) (range 0 8)))
(define (c n) (map (lambda (i) (+ (* i 8) n)) (range 0 8)))
(define (d n) (if (< n 0) ;n=i-j -7<=n<8
(map (lambda (i) (+ (* i 9) (- 0 n))) (range 0 (+ n 8)))
(map (lambda (i) (+ (* i 9) (* n 8))) (range 0 (- 8 n)))))
(define (u n) (if (< n 7) ;n=i+j 0<=n<15
(map (lambda (i) (+ (* i -7) (* n 8))) (range 0 (+ n 1)))
(map (lambda (i) (+ (* i -7) (+ n 49))) (range 0 (- 15 n)))))
(define (bs n)
(let ((i (quotient n 8)) (j (modulo n 8))
(b (make-bit-string 64 #t)))
(for-each (lambda (m) (bit-string-clear! b m))
(append (r i) (c j) (d (- i j)) (u (+ i j))))
b))
(define bss (map bs (range 0 64)))
(do ((i 0 (+ i 1)) (count 0) (bs (make-bit-string 64 #t)))
((= i 60) count) (display (list 'i i))
(let ((bs (bit-string-copy
(bit-string-and bs (list-ref bss i)))))
(do ((j (+ i 1) (+ j 1))) ((= j 61))
(let ((bs (bit-string-copy
(bit-string-and bs (list-ref bss j)))))
(do ((k (+ j 1) (+ k 1))) ((= k 62))
(let ((bs (bit-string-copy
(bit-string-and bs (list-ref bss k)))))
(do ((l (+ k 1) (+ l 1))) ((= l 63))
(let ((bs (bit-string-copy
(bit-string-and bs (list-ref bss l)))))
(do ((m (+ l 1) (+ m 1))) ((= m 64))
(if (bit-string-zero?
(bit-string-and bs (list-ref bss m)))
(set! count (+ count 1))))))))))))
盤のますには, 左上から右上にかけ, そして上から下へ, 0から63まで番号を付ける.
行rは上が0, 下が7(その番号をiとする), 列cは左が0, 右が7(その番号をjとする),
左上から右下への対角線dは, ます7を通る(i=0,j=7)のを-7, ます0を通るのを0,
ます56を通る(i=7, j=0)のを7, 左下から右上への対角線uは, ます0を通る(i=0,j=0)
のを0, ます56を通る(i=7,j=0)のを7, ます63を通る(i=7,j=7)のを14とする.
先頭の関数, r,c,d,uは, 行n, 列n, 下り対角線n, 上り対角線nにいるクイーンが支配する ますの番号を返す.
bssは, ますnのクイーンが支配するますをビット0, それ以外をビット1にした, 64ビット のビット列の配列である。<br>
これだけ用意し, 後は5個のクイーンを, 全面に置きながら, 支配場所を集め, 5個置いた 時に, すべてのます(に対応するビット)が0なら, countを1増やす.
やってみたら, 18秒くらいで, 4860が得られた.

0 件のコメント:
コメントを投稿