一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
1.问题描述
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。
回溯算法求解八皇后问题的原则是:有冲突解决冲突,没有冲突往前走,无路可走往回退,走到最后是答案。为了加快有无冲突的判断速度,可以给每行和两个方向的每条对角线是否有皇后占据建立标志数组。放下一个新皇后做标志,回溯时挪动一个旧皇后清除标志。
2.思路
第一个皇后先放第一行第一列。
第二个皇后放在第二行第一列、然后判断是否OK,如果不0K, 继续放在第二列、第三列、依次把所有列都放完,找到一个合适。
继续第三个皇后, 还是第一列、第二列…直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解。
当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到。
然后回头继续第-一个皇后放第二列,后面继续循环执行前面的步骤
3.代码实现
public class Queue {
int max = 8; //8个皇后
int[] arr = new int[max]; //下标为第几个(即第几行),值为第几列
static int count = 0; //多少个放法
static int judgeCount = 0; //判断了多少次
public static void main(String[] args) {
Queue8 queue8 = new Queue8();
queue8.check(0);
System.out.printf("一共有%d种解法\n",count);
System.out.printf("一共判断了%d次",judgeCount);
}
//用来放置第n个皇后
private void check(int n){
if (n == max){ //n为8相当于是第九个皇后了,说明已经全部放好了
print();
return;
}
for (int i = 0; i < arr.length; i++) {
arr[n] = i;
if (judge(n)){ //不冲突
check(n+1);
}
}
}
//用来第n个皇后判断与前面的所有皇后是否冲突
private boolean judge(int n){
judgeCount++;
for (int i = 0; i < n; i++) {
//是否同列同斜线
if (arr[i] == arr[n] || Math.abs(arr[i]-arr[n]) == Math.abs(i-n)){
return false;
}
}
return true;
}
//输出每一种放法
private void print(){
count++;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}