八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的皇后摆放问题:这时棋盘的大小变为×,而皇后个数也变成。当且仅当 = 1或 ≥ 4时问题有解。
八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔(Max Bezzel)于1848年提出。第一个解在1850年由弗朗兹·诺克(Franz Nauck)给出。并且将其推广为更一般的皇后摆放问题。诺克也是首先将问题推广到更一般的皇后摆放问题的人之一。
在此之后,陆续有数学家对其进行研究,其中包括高斯和康托,1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
1972年,艾兹格·迪杰斯特拉用这个问题为例来说明他所谓结构化编程的能力。他对深度优先搜索回溯算法有着非常详尽的描述2。
八皇后问题在1990年代初期的著名电子游戏第七访客和NDS平台的著名电子游戏《雷顿教授与不可思议的小镇》中都有出现。
八个皇后在8x8棋盘上共有4,426,165,368(64C8)种摆放方法,但只有92个互不相同的解。如果将旋转和对称的解归为一种的话,则一共有12个独立解,具体如下:
下表给出了皇后问题的解的个数包括独立解U(OEIS中的数列A002562)以及互不相同的解D(OEIS中的数列A000170)的个数:
可以注意到六皇后问题的解的个数比五皇后问题的解的个数要少。现在还没有已知公式可以对计算皇后问题的解的个数。
下面是求解n皇后的C代码,在程序中可以自己设置n个皇后以及选择是否打印出具体解。
#include <stdio.h>#define QUEENS 8 /*皇后数量*/#define IS_OUTPUT 1 /*(IS_OUTPUT=0 or 1),Output用于选择是否输出具体解,为1输出,为0不输出*/int A, B, C, k;int inc, *a = A, *b = B + QUEENS, *c = C;void lay(int i) { int j = 0, t, u; while (++j <= QUEENS) if (a + b + c == 0) { k = a = b = c = 1; if (i < QUEENS) lay(i + 1); else { ++inc; if (IS_OUTPUT) { for (printf("(%d)\n", inc), u = QUEENS + 1; --u; printf("\n")) for (t = QUEENS + 1; --t; ) k ? printf("Q ") : printf("+ "); printf("\n\n\n"); } } a = b = c = k = 0; }}int main(void) { lay(1); printf("%d皇后共计%d个解\n", QUEENS, inc); return 0;}