エイト・クイーンのソース置き場 BashもJavaもPythonも!
キャリーチェーン
キャリーチェーンはN27の解を発見したドレスデン大学の研究者が編み出したアルゴリズムです。
Jeffサマーズがミラーとビットマップの組み合わせでN23を発見し、電気通信大学がサマーズのアルゴリズムを並列処理しN24を発見、プロアクティブが対称解除法でN25を発見し、N27でキャリーチェーンによりドレスデン大学が世界一となりました。
Bash版の対称解除法の実行結果を見てみましょう。
Nクイーン問題(15)第三章 対象解除法 ロジック解説
# <> 06Bash_symmetry.sh 対象解除法
# N: Total Unique hh:mm:ss
# 4: 2 1 0:00:00
# 5: 10 2 0:00:00
# 6: 4 1 0:00:00
# 7: 40 6 0:00:00
# 8: 92 12 0:00:00
# 9: 352 46 0:00:00
# 10: 724 92 0:00:02
# 11: 2680 341 0:00:05
# 12: 14200 1787 0:00:26
# 13: 73712 9233 0:02:28
# 14: 365596 45752 0:14:18
# 15: 2279184 285053 1:23:34
N25で、1時間23分かかっています。
Bashだからこその遅さです。CプログラムではN17までは1秒かかりません。
とはいえ、アルゴリズムやロジックを深く知るためには、プログラムのシンタックスに悩むドデカ級のプログラム言語よりも、身近なBash言語のほうが直感的でよいのです。
UNIXを開発したAT&Tベル研究所では、開発者はBashでプロトタイプを作り、その後プログラマがCに移植します。
新しい開発、革新的なロジックを研究することにBashは多くの現場で活躍してきました。CやJavaは、知恵を導入するまえに、構文(シンタックス)の複雑さに気を奪われ、書いた気になる、作った気になる言語と言われています。
では、N27を叩き出したドレスデン大学のソースをBashに移植して、高速化、最適化したソースの実行結果を見てみます。
# <> 07Bash_carryChain.sh
# N: Total Unique hh:mm:ss
# 4: 2 1 0:00:00
# 5: 10 2 0:00:00
# 6: 4 1 0:00:00
# 7: 40 6 0:00:01
# 8: 92 12 0:00:02
# 9: 352 46 0:00:12
# 10: 724 92 0:00:44
# 11: 2680 341 0:02:39
# 12: 14200 1788 0:08:35
# 13: 73712 9237 0:27:05
# 14: 365596 45771 1:30:40
# 15: 2279184 285095 5:59:03
おそい。。。。
遅すぎますね。大丈夫なのでしょうか。
実際、とてつもなく遅いのですが、キャリーチェーンとは
1.対称解除とは比較にならないほど遅い
2.対称解除とは比較にならないほどメモリ消費量が小さい
3.対称解除と比べ、Nが小さいときに遅いが、Nが大きくなるに従って対称解除のスピードに追いつき、N17で対称解除を追い抜き安定して実行を継続する。
4.一方で対称解除は、Nが小さいときは快調だが、Nが大きくなるに従って、board配列を中心にメモリ消費量が爆発的に肥大し、N17以降、高い確率でバースト、システムは停止する。
ということで、キャリーチェーンは、遅いけど安定的に処理し続けるアルゴリズムなのです。
さらに、次の章で紹介する並列処理に極めて高い親和性があるアルゴリズムです。
アルゴリズム
おおまかなアルゴリズムを説明します。
ソースはおおよそ下から積み上げるようにして書きますので、
最初の実行は一番下の「function NQ()」となります。
# 'ボード外側2列を除く内側のクイーン配置処理';
def solve(row,left,down,right):
# 'solve()を呼び出して再帰を開始する';
def process(size,sym):
# 'キャリーチェーン対称解除法';
def carryChainSymmetry(size,n,w,s,e):
# 'クイーンの効きをチェック';
def placement(size,dimx,dimy):
# 'チェーンのビルド';
def buildChain(size):
# 'チェーンの初期化';
def initChain(size):
# 'チェーンの構築';
def carryChain(size):
ロジック解説
まず、NQ()を実行するとcarryChain()を呼び出します。
carrychain()は、チェーンの初期化を行うinitChain()と、チェーンのビルドを行う buildChain()を実行します。
チェーンの初期化を行う initChain()は以下の2行のクイーンが配置できるすべてをブルートフォースで導き出します。ここではクイーンの効きは考慮しません。
1行目の配置を pres_a配列に、2行目の配列をpres_b配列に保存します。
initChain()
+-+-+-+-+-+-+-+
|Q|Q|Q|Q|Q|Q|Q|
+-+-+-+-+-+-+-+
|Q|Q|Q|Q|Q|Q|Q|
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
次にbuildChain()は、上2行に配置します。
buildChain()では配置のたびに placement()を呼び出し、クイーンの効きに問題がないかをチェックします。
ざっくりいうと上1行目のクイーンはミラーのロジックにより、Nの半分しか配置しません。上2行目はNすべてを配置候補とします。
buildChain()
+-+-+-+-+-+-+-+
| | | | | | |Q| ←
+-+-+-+-+-+-+-+
| | | | |Q|x|x| ←
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
上2行に配置できたら、左2列を作成します。
↓↓
+-+-+-+-+-+-+-+
|x|x| | | | |Q|
+-+-+-+-+-+-+-+
|x|x|x|x|Q|x|x|
+-+-+-+-+-+-+-+
|Q|x|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|x|x|x|x| |x|
+-+-+-+-+-+-+-+
|x|x|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|Q|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|x|x|Q|x|x|x|
+-+-+-+-+-+-+-+
左2列が完成したら、下2行を作成します。
クイーンの配置の都度、placement()が呼び出され、クイーンの効きをチェックします。
+-+-+-+-+-+-+-+
|x|x|x|x|x|x|Q|
+-+-+-+-+-+-+-+
|x|x| | |Q|x|x|
+-+-+-+-+-+-+-+
|Q|x| |x|x| |x|
+-+-+-+-+-+-+-+
|x|x|x|x|x| |x|
+-+-+-+-+-+-+-+
|x|x|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|Q|x|x|x|x|x| ←
+-+-+-+-+-+-+-+
|x|x|x|Q|x|x|x| ←
+-+-+-+-+-+-+-+
すでに配置されている場合はそれを許可し、配置したことにします。
下2行を作成したら、右2列を作成します。
+-+-+-+-+-+-+-+
|x|x|x|x|x|x|Q|
+-+-+-+-+-+-+-+
|x|x| |x|Q|x|x|
+-+-+-+-+-+-+-+
|Q|x| |x|x|x|x|
+-+-+-+-+-+-+-+
|x|x|x|x|x|Q|x|
+-+-+-+-+-+-+-+
|x|x|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|Q|x|x|x|x|x|
+-+-+-+-+-+-+-+
|x|x|x|Q|x|x|x|
+-+-+-+-+-+-+-+
↑↑
配置が終わりました。
配置が終わったら、carryChainSymmetry()を呼び出して、対称解除法を実行します。
これまでのsymmetry.shでは1行目のクイーンが角にあるか、ないかで分岐し、クイーンの配置がすべて完了したら対称解除を行ってきました。ようするに処理の最終局面で対称解除を行ってきたわけです。
ですので、ボード情報をboard配列に入れて90度回転を繰り返してきました。この処理はbit処理でなかった(僕がどうやってよいか分からなかった)ため、負荷も高くなってしまいました。
盤面のクイーンの配置すべてを格納したboard配列をまるっと90度回転、さらに90度回転、さらにさらに90度回転と繰り返して、COUNT2,COUNT4,COUNT8のユニーク解を導き出していました。
キャリーチェーンは、盤面の外枠2行2列のみにクイーンを配置します。理由は「対称解除は2行2列に配置されていれば可能」だからです。
まず、2行2列を配置し、対称解除を行い、COUNT2,COUNT4,COUNT8のいずれかである場合にかぎって、内側にクイーンの配置処理に入ります。
すごいですね! 新しいです。
最初に対称解除を行うことができるから、最初からbit処理可能です。そして最後までbit処理で完結できます。
これまでやってきた枝刈りのロジックは、ドレスデン大学のソースにはありませんでしたが、追記しておきました。期待大!ですね。
ですが、激しく遅いのです。残念です。
とはいえ世界一となったこのロジックはただものではありません。極めて優れたロジックで、パッと見だめでもじつはイケてるプログラムなのです。
キャリーチェーン プログラムソース
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import copy
"""
キャリーチェーン版 Nクイーン
詳細はこちら。
【参考リンク】Nクイーン問題 過去記事一覧はこちらから
https://suzukiiichiro.github.io/search/?keyword=Nクイーン問題
エイト・クイーンのプログラムアーカイブ
Bash、Lua、C、Java、Python、CUDAまで!
https://github.com/suzukiiichiro/N-Queens
# 実行
$ python <filename.py>
# 実行結果
bash-3.2$ python 07Python_carryChain.py
size: 5 TOTAL: 10 UNIQUE: 2
bash-3.2$
"""
#
# グローバル変数
TOTAL=0
UNIQUE=0
pres_a=[0]*930
pres_b=[0]*930
COUNTER=[0]*3
B=[]
#
# ボード外側2列を除く内側のクイーン配置処理
def solve(row,left,down,right):
total=0
if not down+1:
return 1
while row&1:
row>>=1
left<<=1
right>>=1
row>>=1 # 1行下に移動する
bitmap=~(left|down|right)
while bitmap!=0:
bit=-bitmap&bitmap
total+=solve(row,(left|bit)<<1,down|bit,(right|bit)>>1)
bitmap^=bit
return total
#
# キャリーチェーン solve()を呼び出して再起を開始する
def process(size,sym):
global B
global COUNTER
# sym 0:COUNT2 1:COUNT4 2:COUNT8
COUNTER[sym]+=solve(
B[0]>>2,
B[1]>>4,
(((B[2]>>2|~0<<size-4)+1)<<size-5)-1,
B[3]>>4<<size-5
)
#
# キャリーチェーン 対象解除
def carryChainSymmetry(size,n,w,s,e):
global B
# n,e,s=(N-2)*(N-1)-1-w の場合は最小値を確認する。
ww=(size-2)*(size-1)-1-w
w2=(size-2)*(size-1)-1
# 対角線上の反転が小さいかどうか確認する
if s==ww and n<(w2-e): return
# 垂直方向の中心に対する反転が小さいかを確認
if e==ww and n>(w2-n): return
# 斜め下方向への反転が小さいかをチェックする
if n==ww and e>(w2-s): return
# 【枝刈り】1行目が角の場合
# 1.回転対称チェックせずにCOUNT8にする
if not B[4][0]:
process(size,2) # COUNT8
return
# n,e,s==w の場合は最小値を確認する。
# : '右回転で同じ場合は、
# w=n=e=sでなければ値が小さいのでskip
# w=n=e=sであれば90度回転で同じ可能性 ';
if s==w:
if n!=w or e!=w: return
process(size,0) # COUNT2
return
# : 'e==wは180度回転して同じ
# 180度回転して同じ時n>=sの時はsmaller? ';
if e==w and n>=s:
if n>s: return
process(size,1) # COUNT4
return
process(size,2) # COUNT8
return
#
# キャリーチェーン 効きのチェック dimxは行 dimyは列
def placement(size,dimx,dimy):
global B
if B[4][dimx]==dimy:
return 1
#
#
# 【枝刈り】Qが角にある場合の枝刈り
# 2.2列めにクイーンは置かない
# (1はcarryChainSymmetry()内にあります)
#
# Qが角にある場合は、
# 2行目のクイーンの位置 t_x[1]が BOUND1
# BOUND1行目までは2列目にクイーンを置けない
#
# +-+-+-+-+-+
# | | | |X|Q|
# +-+-+-+-+-+
# | |Q| |X| |
# +-+-+-+-+-+
# | | | |X| |
# +-+-+-+-+-+
# | | | |Q| |
# +-+-+-+-+-+
# | | | | | |
# +-+-+-+-+-+
if B[4][0]:
#
# 【枝刈り】Qが角にない場合
#
# +-+-+-+-+-+
# |X|X|Q|X|X|
# +-+-+-+-+-+
# |X| | | |X|
# +-+-+-+-+-+
# | | | | | |
# +-+-+-+-+-+
# |X| | | |X|
# +-+-+-+-+-+
# |X|X| |X|X|
# +-+-+-+-+-+
#
# 1.上部サイド枝刈り
# if ((row<BOUND1));then
# bitmap=$(( bitmap|SIDEMASK ));
# bitmap=$(( bitmap^=SIDEMASK ));
#
# | | | | | |
# +-+-+-+-+-+
# BOUND1はt_x[0]
#
# 2.下部サイド枝刈り
# if ((row==BOUND2));then
# if (( !(down&SIDEMASK) ));then
# return ;
# fi
# if (( (down&SIDEMASK)!=SIDEMASK ));then
# bitmap=$(( bitmap&SIDEMASK ));
# fi
# fi
#
# 2.最下段枝刈り
# LSATMASKの意味は最終行でBOUND1以下または
# BOUND2以上にクイーンは置けないということ
# BOUND2はsize-t_x[0]
# if(row==sizeE){
# //if(!bitmap){
# if(bitmap){
# if((bitmap&LASTMASK)==0){
if B[4][0]!=-1:
if(
(dimx<B[4][0] or dimx>=size-B[4][0]) and
(dimy==0 or dimy==size-1)
):
return 0
if(
(dimx==size-1) and
(dimy<=B[4][0] or dimy>=size-B[4][0])
):
return 0
else:
if B[4][1]!=-1:
# bitmap=$(( bitmap|2 )); # 枝刈り
# bitmap=$(( bitmap^2 )); # 枝刈り
#((bitmap&=~2)); # 上2行を一行にまとめるとこうなります
# ちなみに上と下は同じ趣旨
# if (( (t_x[1]>=dimx)&&(dimy==1) ));then
# return 0;
# fi
if B[4][1]>=dimx and dimy==1:
return 0
if( (B[0] & 1<<dimx) or
(B[1] & 1<<(size-1-dimx+dimy)) or
(B[2] & 1<<dimy) or
(B[3] & 1<<(dimx+dimy))
):
return 0
B[0]|=1<<dimx
B[1]|=1<<(size-1-dimx+dimy)
B[2]|=1<<dimy
B[3]|=1<<(dimx+dimy)
B[4][dimx]=dimy
return 1
#
# チェーンのビルド
def buildChain(size):
global B
global pres_a
global pres_b
B=[0,0,0,0,[-1]*size] # Bの初期化
wB=sB=eB=nB=[]
wB=copy.deepcopy(B)
for w in range( (size//2)*(size-3) +1):
B=copy.deepcopy(wB)
B=[0,0,0,0,[-1]*size] # Bの初期化
# 1.0行目と1行目にクイーンを配置
if placement(size,0,pres_a[w])==0:
continue
if placement(size,1,pres_b[w])==0:
continue
# 2.90度回転
nB=copy.deepcopy(B)
mirror=(size-2)*(size-1)-w
for n in range(w,mirror,1):
B=copy.deepcopy(nB)
if placement(size,pres_a[n],size-1)==0:
continue
if placement(size,pres_b[n],size-2)==0:
continue
# 3.90度回転
eB=copy.deepcopy(B)
for e in range(w,mirror,1):
B=copy.deepcopy(eB)
if placement(size,size-1,size-1-pres_a[e])==0:
continue
if placement(size,size-2,size-1-pres_b[e])==0:
continue
# 4.90度回転
sB=copy.deepcopy(B)
for s in range(w,mirror,1):
B=copy.deepcopy(sB)
if placement(size,size-1-pres_a[s],0)==0:
continue
if placement(size,size-1-pres_b[s],1)==0:
continue
# 対象解除法
carryChainSymmetry(size,n,w,s,e)
#
# チェーンの初期化
def initChain(size):
global pres_a
global pres_b
idx=0
for a in range(size):
for b in range(size):
if (a>=b and (a-b)<=1) or (b>a and (b-a<=1)):
continue
pres_a[idx]=a
pres_b[idx]=b
idx+=1
#
# キャリーチェーン
def carryChain(size):
global B
global TOTAL
global UNIQUE
global COUNTER
TOTAL=UNIQUE=0
COUNTER[0]=COUNTER[1]=COUNTER[2]=0
# Bの初期化 [0, 0, 0, 0, [0, 0, 0, 0, 0]]
B=[0]*5 # row/left/down/right/X
B[4]=[-1]*size # X を0でsize分を初期化
initChain(size) # チェーンの初期化
buildChain(size) # チェーンのビルド
# 集計
UNIQUE=COUNTER[0]+COUNTER[1]+COUNTER[2]
TOTAL=COUNTER[0]*2 + COUNTER[1]*4 + COUNTER[2]*8
#
# 実行
size=5
carryChain(size) # 7.キャリーチェーン
print("size:",size,"TOTAL:",TOTAL,"UNIQUE:",UNIQUE)
#
次回は、Nを順番に処理していく「ステップN」をやります。
参考リンク
以下の詳細説明を参考にしてください。
【参考リンク】Nクイーン問題 過去記事一覧
【Github】エイト・クイーンのソース置き場 BashもJavaもPythonも!
Nクイーン問題(50)第七章 マルチプロセス Python編
https://suzukiiichiro.github.io/posts/2023-06-21-04-n-queens-suzuki/
Nクイーン問題(49)第七章 マルチスレッド Python編
https://suzukiiichiro.github.io/posts/2023-06-21-03-n-queens-suzuki/
Nクイーン問題(48)第七章 シングルスレッド Python編
https://suzukiiichiro.github.io/posts/2023-06-21-02-n-queens-suzuki/
Nクイーン問題(47)第七章 クラス Python編
https://suzukiiichiro.github.io/posts/2023-06-21-01-n-queens-suzuki/
Nクイーン問題(46)第七章 ステップNの実装 Python編
https://suzukiiichiro.github.io/posts/2023-06-16-02-n-queens-suzuki/
Nクイーン問題(45)第七章 キャリーチェーン Python編
https://suzukiiichiro.github.io/posts/2023-06-16-01-n-queens-suzuki/
Nクイーン問題(44)第七章 対象解除法 Python編
https://suzukiiichiro.github.io/posts/2023-06-14-02-n-queens-suzuki/
Nクイーン問題(43)第七章 ミラー Python編
https://suzukiiichiro.github.io/posts/2023-06-14-01-n-queens-suzuki/
Nクイーン問題(42)第七章 ビットマップ Python編
https://suzukiiichiro.github.io/posts/2023-06-13-05-n-queens-suzuki/
Nクイーン問題(41)第七章 配置フラグ Python編
https://suzukiiichiro.github.io/posts/2023-06-13-04-n-queens-suzuki/
Nクイーン問題(40)第七章 バックトラック Python編
https://suzukiiichiro.github.io/posts/2023-06-13-03-n-queens-suzuki/
Nクイーン問題(39)第七章 バックトラック準備編 Python編
https://suzukiiichiro.github.io/posts/2023-06-13-02-n-queens-suzuki/
Nクイーン問題(38)第七章 ブルートフォース Python編
https://suzukiiichiro.github.io/posts/2023-06-13-01-n-queens-suzuki/
Nクイーン問題(37)第六章 C言語移植 その17 pthread並列処理完成
https://suzukiiichiro.github.io/posts/2023-05-30-17-n-queens-suzuki/
Nクイーン問題(36)第六章 C言語移植 その16 pthreadの実装
https://suzukiiichiro.github.io/posts/2023-05-30-16-n-queens-suzuki/
Nクイーン問題(35)第六章 C言語移植 その15 pthread実装直前版完成
https://suzukiiichiro.github.io/posts/2023-05-30-15-n-queens-suzuki/
Nクイーン問題(34)第六章 C言語移植 その14
https://suzukiiichiro.github.io/posts/2023-05-30-14-n-queens-suzuki/
Nクイーン問題(33)第六章 C言語移植 その13
https://suzukiiichiro.github.io/posts/2023-05-30-13-n-queens-suzuki/
Nクイーン問題(32)第六章 C言語移植 その12
https://suzukiiichiro.github.io/posts/2023-05-30-12-n-queens-suzuki/
Nクイーン問題(31)第六章 C言語移植 その11
https://suzukiiichiro.github.io/posts/2023-05-30-11-n-queens-suzuki/
Nクイーン問題(30)第六章 C言語移植 その10
https://suzukiiichiro.github.io/posts/2023-05-30-10-n-queens-suzuki/
Nクイーン問題(29)第六章 C言語移植 その9
https://suzukiiichiro.github.io/posts/2023-05-30-09-n-queens-suzuki/
Nクイーン問題(28)第六章 C言語移植 その8
https://suzukiiichiro.github.io/posts/2023-05-30-08-n-queens-suzuki/
Nクイーン問題(27)第六章 C言語移植 その7
https://suzukiiichiro.github.io/posts/2023-05-30-07-n-queens-suzuki/
Nクイーン問題(26)第六章 C言語移植 その6
https://suzukiiichiro.github.io/posts/2023-05-30-06-n-queens-suzuki/
Nクイーン問題(25)第六章 C言語移植 その5
https://suzukiiichiro.github.io/posts/2023-05-30-05-n-queens-suzuki/
Nクイーン問題(24)第六章 C言語移植 その4
https://suzukiiichiro.github.io/posts/2023-05-30-04-n-queens-suzuki/
Nクイーン問題(23)第六章 C言語移植 その3
https://suzukiiichiro.github.io/posts/2023-05-30-03-n-queens-suzuki/
Nクイーン問題(22)第六章 C言語移植 その2
https://suzukiiichiro.github.io/posts/2023-05-30-02-n-queens-suzuki/
Nクイーン問題(21)第六章 C言語移植 その1
N-Queens問://suzukiiichiro.github.io/posts/2023-05-30-01-n-queens-suzuki/
Nクイーン問題(20)第五章 並列処理
https://suzukiiichiro.github.io/posts/2023-05-23-02-n-queens-suzuki/
Nクイーン問題(19)第五章 キャリーチェーン
https://suzukiiichiro.github.io/posts/2023-05-23-01-n-queens-suzuki/
Nクイーン問題(18)第四章 エイト・クイーンノスタルジー
https://suzukiiichiro.github.io/posts/2023-04-25-01-n-queens-suzuki/
Nクイーン問題(17)第四章 偉人のソースを読む「N24を発見 Jeff Somers」
https://suzukiiichiro.github.io/posts/2023-04-21-01-n-queens-suzuki/
Nクイーン問題(16)第三章 対象解除法 ソース解説
https://suzukiiichiro.github.io/posts/2023-04-18-01-n-queens-suzuki/
Nクイーン問題(15)第三章 対象解除法 ロジック解説
https://suzukiiichiro.github.io/posts/2023-04-13-02-nqueens-suzuki/
Nクイーン問題(14)第三章 ミラー
https://suzukiiichiro.github.io/posts/2023-04-13-01-nqueens-suzuki/
Nクイーン問題(13)第三章 ビットマップ
https://suzukiiichiro.github.io/posts/2023-04-05-01-nqueens-suzuki/
Nクイーン問題(12)第二章 まとめ
https://suzukiiichiro.github.io/posts/2023-03-17-02-n-queens-suzuki/
Nクイーン問題(11)第二章 配置フラグの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-17-01-n-queens-suzuki/
Nクイーン問題(10)第二章 バックトラックの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-16-01-n-queens-suzuki/
Nクイーン問題(9)第二章 ブルートフォースの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-14-01-n-queens-suzuki/
Nクイーン問題(8)第一章 まとめ
https://suzukiiichiro.github.io/posts/2023-03-09-01-n-queens-suzuki/
Nクイーン問題(7)第一章 ブルートフォース再び
https://suzukiiichiro.github.io/posts/2023-03-08-01-n-queens-suzuki/
Nクイーン問題(6)第一章 配置フラグ
https://suzukiiichiro.github.io/posts/2023-03-07-01-n-queens-suzuki/
Nクイーン問題(5)第一章 進捗表示テーブルの作成
https://suzukiiichiro.github.io/posts/2023-03-06-01-n-queens-suzuki/
Nクイーン問題(4)第一章 バックトラック
https://suzukiiichiro.github.io/posts/2023-02-21-01-n-queens-suzuki/
Nクイーン問題(3)第一章 バックトラック準備編
https://suzukiiichiro.github.io/posts/2023-02-14-03-n-queens-suzuki/
Nクイーン問題(2)第一章 ブルートフォース
https://suzukiiichiro.github.io/posts/2023-02-14-02-n-queens-suzuki/
Nクイーン問題(1)第一章 エイトクイーンについて
https://suzukiiichiro.github.io/posts/2023-02-14-01-n-queens-suzuki/