1. 规则:有一个 8 x 8 的棋盘,放置皇后棋子,要求:所放的皇后不能在同一排,不能在同一列,不能在同一斜线
2. http://www.4399.com/baidugame/42643.htm 这个是4399里8皇后小游戏的地址
3. 为了理清思路,我以 4 x 4的棋盘为例,code
/**
* 8皇后问题
*/
public class Queue8 {
// 一维数组代表所放皇后的列, 我们默认不把皇后放在同一行
private final int max = 4;
private final int[] array = new int[max];
private static int count = 0;
public static void main(String[] args) {
Queue8 queue8 = new Queue8();
queue8.placeChess(0);
System.out.printf("4 x 4的棋盘解法有%d种\n", count);
}
/**
* 放置棋子
*
* @param n 棋盘行数索引
*/
public void placeChess(int n) {
if (n < 0 || n > max) {
return;
}
if (n == max) {
print();
return;
}
for (int i = 0; i < max; i++) {
array[n] = i; // i就是表示第n行的第i列(n和i都是索引)
if (isNotConflict(n)) {
placeChess(n + 1);
} else { // 这一块代码可能有点多余, 但是可以帮助理解: 如果冲突则将棋子放到下一列
continue;
}
}
}
/**
* 判断第n行放的皇后是否和其他行冲突
*
* @param n 行索引
* @return boolean
*/
private boolean isNotConflict(int n) {
// 拿出第n行前面的所有行, 一行一行的和第n行做对比(array[n]表示第n行的第array[n]列, array[i]同理)
for (int i = 0; i < n; i++) { // 这里出错了一次: 一开始写成i < max, 结果放置第一个棋子时出错, 导致以后的都会错
// 第一种情况:同一行,不用判断。因为我们默认的摆放就是不在同一行
// 第二种情况:同一列, array[i] 和 array[n] 就表示第i行和第n行的列数, 相等就是在同一列
// 第三种情况:同一斜线, 在同一斜线的斜率的绝对值应该等于1, 举个例子坐标(2, 1)和坐标(3, 0)在同一条斜线上(或者这么说, 在一条斜线上的两个点x轴与y轴的差值的绝对值相同)
if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
return false;
}
}
return true;
}
/**
* 打印皇后位置
*/
private void print() {
count++;
for (int value : array) {
System.out.print(value + " ");
}
System.out.println();
}
}
// 执行的结果
1 3 0 2
2 0 3 1
4 x 4的棋盘解法有2种
4. 画图,看一下它的执行思路
5. 总结
1)代码不多,但是理解起来其实还是挺费劲的,就是要对递归求解时有个印象。
2)每一层都要开一个方法栈,以 4 x 4的棋盘为例,最多开五个栈:
- 前四个栈方法中,每个方法栈中都要执行for循环,且参数i都需要从0遍历到3,没有跳步
- 第五个栈的作用是找到解法之后,打印解法并终止递归