看了下别的地方的源码,注释太少,直接写了一下,反过来重看了下别的实现,对比精简了下。
原先做法是,假如递归到r行,则对0-r行的所有坐标 以 列、左上、右上方向分别映射到了三个数组,看数组标记是否在三个方向上有重复的皇后。实际递归前r-1行皇后位置都是验证正确的,不用形成互相检测。
package com.superzlc;
/**
* 八皇后计算
* @author superzlc
*
*/
public class TestEightQueen {
public static void main(String[] args) {
TestEightQueen queen = new TestEightQueen();
long start = System.nanoTime();
queen.calc();
System.out.println((System.nanoTime() - start) / 1000000f);
}
// 8行8列棋盘
private static final int row_size = 8;
private static final int col_size = 8;
// 用于表示所有皇后位置,8行,每行的值是几表示在这行第几列是皇后,列范围0-7,-1表示没有皇后
private int[] rows = new int[row_size];
int resultIndex = 0;
// 设置为皇后
private void setQueen(int r, int c) {
rows[r] = c;
}
// 判断为皇后
private boolean isQueen(int r, int c) {
return rows[r] == c;
}
// 打印结果
private void printResult() {
StringBuilder sb = new StringBuilder();
sb.append("Result ").append(++resultIndex).append(":\n");
for (int r = 0; r < row_size; r++) {
for (int c = 0; c < col_size; c++)
sb.append(isQueen(r, c) ? 'Q' : '.');
sb.append('\n');
}
System.out.println(sb);
}
// 检测(rr, cc)位置皇后满足条件
private boolean checkQueenValid(int rr, int cc) {
// 按递归前rr-1行的皇后肯定是满足的,只测试rr行皇后与之前行是否冲突
for (int r = 0; r < rr; r++) {
// 列方向检测
if (isQueen(r, cc))
return false;
// 左上方向检测
int c_lu = cc - (rr - r); // 坐标 cc - (rr - r)
if (isQueen(r, c_lu))
return false;
// 右上方向检测
int c_ru = cc + (rr - r); // 坐标 cc + (rr - r)
if (isQueen(r, c_ru))
return false;
}
return true;
}
// 测试第r行满足条件
private void tryRow(int r) {
// 第r行皇后位置为0-7,挨次测试是否合法
for (int c = 0; c < col_size; c++) {
if (checkQueenValid(r, c)) { // 测试合法
setQueen(r, c);
if (r == row_size - 1) { // 测试合法且是最后一行,打印结果
printResult();
} else { // 测试合法且非最后一行,继续测试下一行
tryRow(r + 1);
}
}
}
}
public void calc() {
tryRow(0);
System.out.println("result count: " + this.resultIndex);
}
}