1、皇后问题解决思路:使用回溯法解决,也就是通常所说的利用树的深度优先搜索求解。即沿着一条路径往下走,如果走不通,那就往回走,尝试另一条路径。
皇后问题的求解过程中,每一个树结点都可以看做是棋局的局部布局或者是完整布局。根结点表示棋局的原始状态,没有任何棋子。之后的层与层之间表示一种状态转换,状态转换的过程就是构造树的过程,也就是树的深度优先搜索的过程。在状态转换的任何时刻,都需要满足约束条件:任何时刻两个棋子不能位于同一行、同一列、或者同一对角线(正对角线、反对角线)。
2、算法实现考虑的问题
①、棋盘及解的表示:最直观的表示方法是使用二维数组,但是二维数组在表示棋盘的时候处理起来不太方便,因此,最有效的表示方法是用一维整型数组x[i]表示棋盘及解。x[i]表示第i行的皇后放置在第x[i]列。
②、放置皇后:将dii个皇后放置在第j个位置。即x[i]=j;
③、约束条件:
不在同一行:每一行只放置一个皇后,从而保证了两个皇后不可能同时在同一行中。
不在同一列:x[i]≠x[k],k = 1,2…i-1;即第x[i]列与之前的(i-1)列都不相同。
不在正对角线上:x[i]-i≠x[k]-k;即列号减去行号的值不相等。因为若是在同一对角线上,那么该差值必然相等。
不在反对角线上:x[i]+i≠x[k]+k;这里道理也是一样的。
综合两个对角线的约束条件:abs(x[i]-x[k])≠abs(i-k)
④、终止条件:对于n皇后问题,假设用i表示皇后编号,从i=1开始放置皇后,那么当i>=n时终止。
3、皇后问题Java代码实现
public class Queen {
int n; // n:需要放置的皇后个数
int ct; // 满足要求的合法解的个数
int[] x; // 表示棋盘及解的一维数组
// 构造函数
public Queen(int n) {
this.n = n;
this.ct = 0;
x = new int[n+1]; // 棋盘下标从1开始,所以申请数组长度是n+1
}
// 递归摆放皇后
public void setQueen (int i) {
// 得到一个满足要求的皇后放置方式,输出位置表示
if (i > n) {
output ();
ct++;
return;
}
for (int j = 1; j <= n; j++) {
x[i] = j;
if (constraint (i)) {
setQueen(i+1);
} else {
x[i] = 0;
}
}
}
// 检查摆放位置是否合法
public boolean constraint (int i) {
for (int k = 1; k < i; k++) {
if (x[i] == x[k] || (Math.abs(x[i]-x[k]) == Math.abs(i-k))) {
return false;
}
}
return true;
}
// 输出合法解
public void output () {
int i;
System.out.print("(");
for (i = 1; i <= n; i++) {
System.out.printf("%4d", x[i]);
}
System.out.println(" )");
}
// 主函数测试
public static void main(String[] args) {
Queen queen = new Queen(8);
queen.setQueen(1);
System.out.println(queen.ct);
}
}
运行结果:
( 1 5 8 6 3 7 2 4 ):表示第一行的皇后放置于第一列;第二行皇后放置于第五列;第三行皇后放置于第八列…以此类推。
( 1 5 8 6 3 7 2 4 )
( 1 6 8 3 7 4 2 5 )
( 1 7 4 6 8 2 5 3 )
( 1 7 5 8 2 4 6 3 )
( 2 4 6 8 3 1 7 5 )
( 2 5 7 1 3 8 6 4 )
( 2 5 7 4 1 8 6 3 )
( 2 6 1 7 4 8 3 5 )
( 2 6 8 3 1 4 7 5 )
( 2 7 3 6 8 5 1 4 )
( 2 7 5 8 1 4 6 3 )
( 2 8 6 1 3 5 7 4 )
( 3 1 7 5 8 2 4 6 )
( 3 5 2 8 1 7 4 6 )
( 3 5 2 8 6 4 7 1 )
( 3 5 7 1 4 2 8 6 )
( 3 5 8 4 1 7 2 6 )
( 3 6 2 5 8 1 7 4 )
( 3 6 2 7 1 4 8 5 )
( 3 6 2 7 5 1 8 4 )
( 3 6 4 1 8 5 7 2 )
( 3 6 4 2 8 5 7 1 )
( 3 6 8 1 4 7 5 2 )
( 3 6 8 1 5 7 2 4 )
( 3 6 8 2 4 1 7 5 )
( 3 7 2 8 5 1 4 6 )
( 3 7 2 8 6 4 1 5 )
( 3 8 4 7 1 6 2 5 )
( 4 1 5 8 2 7 3 6 )
( 4 1 5 8 6 3 7 2 )
( 4 2 5 8 6 1 3 7 )
( 4 2 7 3 6 8 1 5 )
( 4 2 7 3 6 8 5 1 )
( 4 2 7 5 1 8 6 3 )
( 4 2 8 5 7 1 3 6 )
( 4 2 8 6 1 3 5 7 )
( 4 6 1 5 2 8 3 7 )
( 4 6 8 2 7 1 3 5 )
( 4 6 8 3 1 7 5 2 )
( 4 7 1 8 5 2 6 3 )
( 4 7 3 8 2 5 1 6 )
( 4 7 5 2 6 1 3 8 )
( 4 7 5 3 1 6 8 2 )
( 4 8 1 3 6 2 7 5 )
( 4 8 1 5 7 2 6 3 )
( 4 8 5 3 1 7 2 6 )
( 5 1 4 6 8 2 7 3 )
( 5 1 8 4 2 7 3 6 )
( 5 1 8 6 3 7 2 4 )
( 5 2 4 6 8 3 1 7 )
( 5 2 4 7 3 8 6 1 )
( 5 2 6 1 7 4 8 3 )
( 5 2 8 1 4 7 3 6 )
( 5 3 1 6 8 2 4 7 )
( 5 3 1 7 2 8 6 4 )
( 5 3 8 4 7 1 6 2 )
( 5 7 1 3 8 6 4 2 )
( 5 7 1 4 2 8 6 3 )
( 5 7 2 4 8 1 3 6 )
( 5 7 2 6 3 1 4 8 )
( 5 7 2 6 3 1 8 4 )
( 5 7 4 1 3 8 6 2 )
( 5 8 4 1 3 6 2 7 )
( 5 8 4 1 7 2 6 3 )
( 6 1 5 2 8 3 7 4 )
( 6 2 7 1 3 5 8 4 )
( 6 2 7 1 4 8 5 3 )
( 6 3 1 7 5 8 2 4 )
( 6 3 1 8 4 2 7 5 )
( 6 3 1 8 5 2 4 7 )
( 6 3 5 7 1 4 2 8 )
( 6 3 5 8 1 4 2 7 )
( 6 3 7 2 4 8 1 5 )
( 6 3 7 2 8 5 1 4 )
( 6 3 7 4 1 8 2 5 )
( 6 4 1 5 8 2 7 3 )
( 6 4 2 8 5 7 1 3 )
( 6 4 7 1 3 5 2 8 )
( 6 4 7 1 8 2 5 3 )
( 6 8 2 4 1 7 5 3 )
( 7 1 3 8 6 4 2 5 )
( 7 2 4 1 8 5 3 6 )
( 7 2 6 3 1 4 8 5 )
( 7 3 1 6 8 5 2 4 )
( 7 3 8 2 5 1 6 4 )
( 7 4 2 5 8 1 3 6 )
( 7 4 2 8 6 1 3 5 )
( 7 5 3 1 6 8 2 4 )
( 8 2 4 1 7 5 3 6 )
( 8 2 5 3 1 7 4 6 )
( 8 3 1 6 2 5 7 4 )
( 8 4 1 3 6 2 7 5 )
92
主要参考《数据结构(Java语言描述)》丁海军著P186-P190