问题描述
八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
问题历史
八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
算法原理
回溯的思想是:假设某一行为当前状态,不断检查该行所有的位置是否能放一个皇后,检索的状态有两种:
(1)先从首位开始检查,如果不能放置,接着检查该行第二个位置,依次检查下去,直到在该行找到一个可以放置一个皇后的地方,然后保存当前状态,转到下一行重复上述方法的检索。
(2)如果检查了该行所有的位置均不能放置一个皇后,说明上一行皇后放置的位置无法让所有的皇后找到自己合适的位置,因此就要回溯到上一行,重新检查该皇后位置后面的位置。
问题解法(java)
public class Queen {
/** 皇后数量 */
private static int num = 8;
/** 同列是否有皇后,1表示有 */
private static int[] column = new int[num];
/** 左上至右下是否有皇后 */
private static int[] lup = new int[2*num - 1];
/** 右上至左下是否有皇后 */
private static int[] rup = new int[2*num - 1];
/** 解答 */
private static int[] queen = new int[num];
/** 序号 */
private static int index;
/**
* 回溯法求解八皇后问题
* @param i
*/
public static void backtrack(int i) {
if (i >= num) {
System.out.println("num:" + ++index);
print();
return;
}
for (int j = 0; j < column.length; j++) {
if (column[j] == 0 && lup[num - j - 1 + i] == 0 && rup[i + j] == 0) {
queen[i] = j; //使用皇后在当前行中的序号填充当前位置
column[j] = lup[num - j - 1 + i] = rup[i + j] = 1;
backtrack(i + 1);
column[j] = lup[num - j - 1 + i] = rup[i + j] = 0;
}
}
}
/**
* 打印
*/
public static void print(){
for (int i = 0; i < queen.length; i++) {
for (int j = 0; j < queen.length; j++) {
System.out.print(queen[i] == j ? "1 " : "0 ");
}
System.out.println();
}
System.out.println();
}
public static void main(String[] args) {
backtrack(0);
}
}