八皇后問題

八皇后問題是一個以國際象棋為背景的問題：如何能夠在8×8的國際象棋棋盤上放置八個皇后，使得任何一個皇后都無法直接吃掉其他的皇后？為了達到此目的，任兩個皇后都不能處於同一條橫行、縱列、正斜線或反斜線。八皇后問題可以推廣為更一般的n皇后擺放問題：這時棋盤的大小變為n×n，而皇后個數也變成n。當且僅當n = 1或n ≥ 4時問題有解。

**歷史**
八皇后問題最早是由西洋棋棋手Max Bezzel（Max Bezzel）於1848年提出。第一個解在1850年由弗朗茲·諾克（Franz Nauck）給出。並且將其推廣為更一般的n皇后擺放問題。諾克也是首先將問題推廣到更一般的n皇后擺放問題的人之一。
在此之後，陸續有數學家對其進行研究，其中包括高斯和康託，1874年，S.岡德爾提出了一個通過行列式來求解的方法，這個方法後來又被J.W.L.格萊舍加以改進。
1972年，艾茲格·迪傑斯特拉用這個問題為例來說明他所謂結構化編程的能力。他對深度優先搜索回溯算法有著非常詳盡的描述2。

**解題方法**
八個皇后在8x8棋盤上共有4,426,165,368（64C8）種擺放方法，但皇后間互不攻擊只有11×8 + 1×4 = 92個“可行解”。如果將在旋轉和反射下重合的可行解歸為一種的話，則一共有12個“獨立解”（fundamental solution），具體如下：
一個獨立解通常有8個變體（含其最初形式），可以先對其進行旋轉90°、180°和270°，加上其最初形式形成4個旋轉變體，再針對一個固定位置比如縱軸進行反射（字母p的垂直反射是字母q），從而得到8個變體。但獨立解10旋轉180°形式與最初形式重合，並且旋轉270°形式與旋轉90°形式重合，所以只有4種變體即自身及其反射和90°旋轉及其反射。
獨立解11具有額外的性質無三皇后在一線。
獨立解3的旋轉90°再垂直反射（效果同於45°反射）的變體，體現了階梯狀模式而被稱為“樓梯解”，n皇后問題對n ≥ 4可通過特定公式得到樓梯解：
# 如果n除以6的餘數不是2或者3，則這個列表簡單的就是不大於n的所有偶數以及隨後的所有奇數。
# 否則，寫出偶數和奇數的單獨列表，比如：(2, 4, 6, 8 – 1, 3, 5, 7)。
# 如果餘數是2，在奇數列表中交換1和3並移動5到末尾，比如：(3, 1, 7, 5)。
# 如果餘數是3，在偶數列表中移動2到末尾並在奇數列表中移動1和3到末尾，比如：(4, 6, 8, 2 – 5, 7, 9, 1, 3)。
# 將奇數列表附加在偶數列表之後並從左至右的在這些橫行上放置皇后，比如：(a2, b4, c6, d8, e3, f1, g7, h5)。
八皇后問題的12個獨立解之間沒有由數學性質決定出的次序，這裡的獨立解次序和所採用的變體是求獨立解的特定搜索算法的輸出結果（第一個解在棋盤左下角或左上角有一個皇后），不加以人為調整，比如：將獨立解3的樓梯變體放在最前，將獨立解10放在最後等等。

**解的個數**
下表給出了n皇后問題的解的個數包括獨立解Uid=A002562以及可行解Did=A000170的個數：
可以注意到六皇后問題的解的個數比五皇后問題的解的個數要少。現在還沒有已知公式可以對n計算n皇后問題的解的個數。

**示例程序**

**求獨立解**

**Python語言**
下面採用Python語言在致力保持不可變性原則下，生成八皇后問題的12個獨立解：
def queens(n):
def q(pl, r):
def place(c): 
return r+c not in pl1 and r-c not in pl2
return ((pl0+c, pl1|{r+c}, pl2|{r-c}, pl3-{c})
for c in pl3 if place(c))
def pipeline(pl, i):
for ipl in q(pl, i):
if i+1 
這裡的算法核心環節是生成器委託yield from。將這段代碼保存入queens.py文件中，下面演示其執行結果：
$ python3 ./queens.py
'a1', 'b7', 'c5', 'd8', 'e2', 'f4', 'g6', 'h3'
'a1', 'b7', 'c4', 'd6', 'e8', 'f2', 'g5', 'h3'
'a6', 'b1', 'c5', 'd2', 'e8', 'f3', 'g7', 'h4'
'a4', 'b1', 'c5', 'd8', 'e2', 'f7', 'g3', 'h6'
'a5', 'b1', 'c8', 'd4', 'e2', 'f7', 'g3', 'h6'
'a3', 'b1', 'c7', 'd5', 'e8', 'f2', 'g4', 'h6'
'a5', 'b1', 'c4', 'd6', 'e8', 'f2', 'g7', 'h3'
'a7', 'b1', 'c3', 'd8', 'e6', 'f4', 'g2', 'h5'
'a5', 'b1', 'c8', 'd6', 'e3', 'f7', 'g2', 'h4'
'a5', 'b3', 'c1', 'd7', 'e2', 'f8', 'g6', 'h4'
'a5', 'b7', 'c1', 'd4', 'e2', 'f8', 'g6', 'h3'
'a6', 'b3', 'c1', 'd8', 'e4', 'f2', 'g7', 'h5'

**jq語言**
下面採用純函數式編程語言jq，生成八皇后問題的12個獨立解：
def queens(n):
def q: . as $pl 

$pl4 as $r 

$pl3 as $cl | $cl | . as $c

tostring) as $k0

tostring) as $k1

def place: 
($k0 | in($pl1) | not)
and ($k1 | in($pl2) | not); 
select(place)

$pl0+$c, $pl1+{$k0:null},
$pl2+{$k1:null}, $cl-$c, $r+1;
def pipeline(n): 
q | if n > 1 then pipeline(n-1) end;
def toletter: 
"abcdefghijklmnopqrstuvwxyz".:.+1;
def fund_solut(f):
def inverse: . as $xl

reduce range(0; n) as $i
(; .+ index($i));
def variants:
., inverse | map(., reverse)

map(., map(n-1-.)) 

add);
foreach f as $i 
(null, {}; .1 as $ml

variants) as $nl

if all($nl; in($ml) | not) then
$i, ($ml | .$nl=null)
else
null, $ml end;
.0)

select (. != null);
fund_solut(, {}, {}, range(0; n), 0

.0) 

to_entries

sort;
queens(8)
這裡的算法核心環節是管道機制。將這段代碼保存入queens.jq文件中，下面演示其執行結果：
$ jq -nc -f ./queens.jq 
"a1","b7","c5","d8","e2","f4","g6","h3"
"a1","b7","c4","d6","e8","f2","g5","h3"
"a6","b1","c5","d2","e8","f3","g7","h4"
"a4","b1","c5","d8","e2","f7","g3","h6"
"a5","b1","c8","d4","e2","f7","g3","h6"
"a3","b1","c7","d5","e8","f2","g4","h6"
"a5","b1","c4","d6","e8","f2","g7","h3"
"a7","b1","c3","d8","e6","f4","g2","h5"
"a5","b1","c8","d6","e3","f7","g2","h4"
"a5","b3","c1","d7","e2","f8","g6","h4"
"a5","b7","c1","d4","e2","f8","g6","h3"
"a6","b3","c1","d8","e4","f2","g7","h5"

**求可行解**

**Icon語言**
下面採用Icon語言，生成八皇后問題的92個可行解：
global n
procedure main()
local i, r, s, u, v, x
n := 8
s := "abcdefghijklmnopqrstuvwxyz"
every x := pipeline(1) do {
r := 
every i := 1 to n do put(r, sxi 
i)
u := sort(r)
v := get(u)
every v 
**"," 

u
write(v)
}
end
procedure pipeline(i)
if i 
這裡的算法核心環節是可逆賦值運算。將這段代碼保存入queens.icn文件中，下面演示其執行結果並提取其92個解中的前兩個解：
$ icon ./queens.icn | wc -l
92
$ icon ./queens.icn | sed -n '1,2p'
a1,b7,c5,d8,e2,f4,g6,h3
a1,b7,c4,d6,e8,f2,g5,h3

**Python語言**
下面採用Python語言基於共享變量，生成八皇后問題的92個可行解：
def queens(n):
col = False*n
down = False*(n*2-1)
up = False*(n*2-1)
def q(r):
def place(c): 
return colc == False == downr+c == upr-c
for c in range(0, n):
if place(c):
colc = downr+c = upr-c = True
yield c
colc = downr+c = upr-c = False
def pipeline(i):
for r in q(i):
if i+1 
這裡的算法核心環節是在生成器之間共享靜態變量。將這段代碼保存入queens.py文件中，下面演示其執行結果並提取其92個解中的前兩個解：
$ python3 ./queens.py | wc -l
92
$ python3 ./queens.py | sed -n '1,2p'
'a1', 'b7', 'c5', 'd8', 'e2', 'f4', 'g6', 'h3'
'a1', 'b7', 'c4', 'd6', 'e8', 'f2', 'g5', 'h3'
這個算法在8個橫行上執行縱列選擇函數q(r)的次數分別為：1, 8, 42, 140, 344, 568, 550, 312，共計1965次，q(r)在每個橫行上針對縱列執行函數place(c)的次數都是8，每橫行的選擇數分別為：8, 64, 336, 1120, 2752, 4544, 4400, 2496，總計15720次，其中每橫行的成功存乎最終結果者之數分別為：8, 36, 62, 80, 90, 90, 92, 92，總計550個。
可以進一步將其寫為下面的Python代碼，其執行方式和結果同於前述：
def queens(n):
cs = 0*n
cl = *range(0, n)
down = False*(n*2-1)
up = False*(n*2-1)
def q(r):
def place(c): 
return downr+c == False == upr-c
for i, c in enumerate(cl):
if place(c):
csr = c
del cli
downr+c = upr-c = True
yield None
cl.insert(i, c)
downr+c = upr-c = False
def pipeline(i):
for _ in q(i):
if i+1 
這個算法在8個橫行上執行縱列選擇函數q(r)的次數分別為：1, 8, 42, 140, 344, 568, 550, 312，共計1965次，q(r)在8個橫行上針對縱列執行函數place(c)的次數分別為：8, 7, 6, 5, 4, 3, 2, 1，每橫行的選擇數分別為：8, 56, 252, 700, 1376, 1704, 1100, 312，總計5508次，其中每橫行的成功存乎最終結果者之數分別為：8, 36, 62, 80, 90, 90, 92, 92，總計550個。
下面將其寫為過程式Python代碼，其執行方式和結果同於前述：
def queens(n):
cs = 0*n
cl = *range(0, n)
down = False*(n*2-1)
up = False*(n*2-1)
rl = *n
toletter = lambda x: \
'abcdefghijklmnopqrstuvwxyz'x
def q(r):
if r 
最後將其寫為指令式Python代碼，其執行方式和結果同於前述：
def queens(n):
cs = 0*n
ps = 0*n
cl = *range(0, n)
down = False*(n*2-1)
up = False*(n*2-1)
rl = *n
toletter = lambda x: \
'abcdefghijklmnopqrstuvwxyz'x
r = 0
while r >= 0:
p = psr
if p != 0:
c = csr
cl.insert(p-1, c)
downr+c = upr-c = False
for i, c in enumerate(clp:):
if downr+c == False == upr-c:
csr = c
psr = p+i+1
break
if p != psr:
del clp+i
downr+c = upr-c = True
r += 1
else:
psr = 0
r -= 1
if r == n:
for k, v in enumerate(cs):
rlk = toletter(v)+str(k+1)
print(sorted(rl))
r -= 1
queens(8)

**C語言**
下面是求解n皇后的C代碼，在程序中可以自己設置n個皇后以及選擇是否打印出具體解。
#include 
#define QUEENS       8 /*皇后數量*/
#define IS_OUTPUT    1 /*(IS_OUTPUT=0 or 1)，Output用於選擇是否輸出具體解,為1輸出，為0不輸出*/
int AQUEENS + 1, BQUEENS * 3 + 1, CQUEENS * 3 + 1, kQUEENS + 1QUEENS + 1;
int inc, *a = A, *b = B + QUEENS, *c = C;
void lay(int i) {
int j = 0, t, u;
while (++j 
使用回溯法進行求解八皇后問題
#include
#define PRINTF_IN 1 //定義是否打印，1：打印，0：不打印
int queens(int Queens){
int i, k, flag, not_finish=1, count=0;
//正在處理的元素下標，表示前i-1個元素已符合要求，正在處理第i個元素
	int aQueens+1;    //八皇后問題的皇后所在的行列位置，從1幵始算起，所以加1
i=1;
a1=1;  //為數組的第一個元素賦初值
printf("%d皇后的可能配置是:",Queens);
while(not_finish){  //not_finish=l:處理尚未結束
while(not_finish && i1 && ai==Queens)
ai=1;  //當ai為Queens時將ai的值置1
else
if(i==1 && ai==Queens)
not_finish=0;  //當第一位的值達到Queens時結束
else
ai++;  //將ail的值取下一個值
}else if(ai == Queens)
ai=1;
else
ai++;  //將ai的值取下一個值
}else if(++i

**Pascal語言**
以下列出尼克勞斯·維爾特的Pascal語言程序。此程序找出了八皇后問題的一個解。
program eightqueen1(output);

var i : integer; q : boolean;
a : array 1 .. 8 of boolean;
b : array 2 .. 16 of boolean;
c : array -7 .. 7 of boolean;
x : array 1 .. 8 of integer;

procedure try( i : integer; var q : boolean);
var j : integer;
begin 
j := 0;
repeat 
j := j + 1; 
q := false;
if a j and b i + j and c i - j then
begin 
x i     := j;
a j     := false; 
b i + j := false; 
c i - j := false;
if i 

**Java語言**
使用回溯法進行求解八皇后問題(Java版本)，可直接複製到N-Queens - LeetCode測試。
class Solution {
public List> solveNQueens(int n) {
List> results = new ArrayList();
// 使用 char 是為了展示結果時，直接使用 new String(char)。
// 一般情況下，使用 boolean 即可。
char result = new charnn;
for (int i = 0; i > results, char result, int x) {
for (int j = 0; j = 0 && j >= 0; --i, --j) {
if (resultij == 'Q') {
return false;
}
}
// ...
// ... ...... (x-1, y+1)
// ... (x, y)
for (int i = x - 1, j = y + 1; i >= 0 && j > results, char result) {
List list = new ArrayList(result.length);
for (char value : result) {
list.add(new String(value));
}
results.add(list);
}
}

**C++語言**
#include "iostream"
#include "cmath"
using namespace std;

#define Max 20      //定義棋盤的最大值 
int aMax;
int show(int S)    //定義出函數
{
	int i,p,q;
	int bMaxMax={0};     //定義且初始化b1輸出模組 

	for(i=1;i0)
	{
		if(knum)     //若滿足輸出數組的要求就輸出該數組 
			{
				count++;
				printf("%d:  ",count);
				show(num);    //調用輸出函數show()
			}
			k--;      //棋子位置不符合要求則退回前一步
			ak++;   //繼續尋找下一列位置
		}
	}
	printf("總共有 %d \n",count,"個");
}

int main(void)
{
	int N,d;
	do
	{
		printf("                  N皇后問題的解(N0&&N

**大眾文化**
在1990年代初期的著名電腦遊戲《第七訪客》中，伊格（Ego，玩家）在史陶夫的府邸的遊戲室裡碰到的象棋問題正是八個皇后問題pages=48-49,289-290。八皇后問題還在NDS平臺的著名電子遊戲《雷頓教授與不可思議的小鎮》中出現。

**延伸閱讀**
 url=https://archive.org/details/acrossboardma00watk- O.-J. Dahl, E. W. Dijkstra, C. A. R. Hoare Structured Programming, Academic Press, London, 1972 0-12-200550-3 see pp. 72–82 for Dijkstra's solution of the 8 Queens problem.- dead-url=no- dead-url=no -  On The Modular N-Queen Problem in Higher Dimensions date=20140616193131 , Ricardo Gomez, Juan Jose Montellano and Ricardo Strausz (2004), Instituto de Matematicas, Area de la Investigacion Cientifica, Circuito Exterior, Ciudad Universitaria, Mexico.- dead-url=no

**參考資料**

**外部鏈接**
 id=QueensProblem- sblendorio/queens-cpm Eight Queens Puzzle in Turbo Pascal for CP/M- gitpel/python-for-fun/blob/master/eight-queens.py Eight Queens Puzzle one line solution in Python-  Solutions in more than 100 different programming languages (on Rosetta Code)