在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有 76 种方案。1854 年在柏林的象棋杂志上不同的作者发表了 40 种不同的解,后来有人用图论的方法解出 92 种结果。(这个问题也一共有92种解法)
思路分析
- 第一个皇后放置在第一行第一列
- 第二个皇后放置在第二行第一列,判断是否满足条件,如果不满足,继续放置在第三列、第四列,直到满足条件为止
- 继续放置后面的皇后,直到所有皇后放置的地方均满足条件
- 当得到一个正确的解之后,最后得到正解的栈会退回到上一个栈,此时开始进行回溯,直到将第一个皇后放置在第一列的所有正解全部得到
- 然后回头继续将第一个皇后放置在第一行第二列,后面开始循环步骤1,2,3,4。直到所有的解全部得到,所有的解包括,将第一个皇后放置在第三列、第四列直到第八列后面的皇后所有摆放均满足条件
这里说明一下,这里八皇后摆放是在一个棋盘上进行,理论上应该创建一个二维数组,但是通过算法,以为数组即可解决问题。
例子:八皇后中,用一维数组解决,其中有一个解为arr[8]={0,4,7,5,2,6,1,3},在这里arr[i]=value表示第i+1个皇后放在第i+1行的第value+1列即arr[0]=1表示第1个皇后在第1行的第1列;arr[1]=4表示第2个皇后在第2行的第5列。
接下来是代码部分
public class Queue8 {
static int count;
// 一般都是用二维数组来表示棋盘的行和列,但是在本题中八皇后本身就可以表示行,比如第一个皇后可以用0来表示
// 比如,在八皇后问题的92种解法有一个摆放的位置是{0,4,7,5,2,6,1,3},这里arr[0]=0就表示第一个皇后在第一行第一列的位置,
// arr[1]=4表示第二个皇后摆放的位置是在第二行的第5列,也就是说皇后最后的位置用一维数组表示即为:arr[i]=val,表示第i+1个皇后
// 放在第i+1行的第val+1列上
int[] arr = new int[8];
int max = 8;
// 先写一个打印的方法,将皇后摆放的位置打印出来,同时,没打印一个结果就将count++,最后显示count有多少种解法
public void print() {
count++;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// 写一个摆放皇后的方法
public void put(int n) {
if (n == max) { //n=8时,八个皇后就放置好
print();
return;
}
//这里将第一个皇后在第一列所有正解全部得到后,就开始回溯,摆放第一个皇后在第二列的所有正解。比如说第一个皇后的在第一列
//的所有正解摆放完毕,递归就会向上一层开始回溯,直到回溯到最开始的循环部分,然后继续走循环,i+1(将皇后放在后一个位置)
//然后又开始进行递归,直到退出最开始的大循环,就代表所有正解全部得到
for (int i = 0; i < max; i++) {
// 先将皇后放在该行的第一列,也就是(n,0)的位置,因为最后测试的时候第一个皇后为0,所以n可以直接表示二维数组的行数
arr[n] = i;
// 然后判断该皇后摆放的位置是否满足题目规则,写一个方法判断
// 如果皇后摆放的位置冲突,则继续循环将皇后摆放在该行的下一列,直到位置不冲突为止;如果摆放的位置不冲突,递归继续摆放下一个皇后
if (judge(n)) {
put(n + 1);
}
}
}
// 八皇后的问题是将8的皇后的棋子摆在棋盘上,每个皇后不能在同一行同一列以及同一个对角线上,所以写一个方法来判断
// 第n个皇后的位置和前面n-1个皇后的位置受否冲突
public boolean judge(int n) {
for (int i = 0; i < n; i++) {
// arr[i] == arr[n]判断所有皇后是否在同一列
// Math.abs(n - i) == Math.abs(arr[n] - arr[i]判断所有皇后是否在同一斜线
if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) {
return false;
}
}
return true;
}
// 主方法测试
public static void main(String[] args) {
Queue8 queue8 = new Queue8();
queue8.put(0);// 从第一个皇后开始摆放
System.out.println("一共有" + count + "种解法");
}
}