利用Java解决八皇后问题
概述
八皇后问题,一个古老而著名的问题,是回溯法的典型案例。八皇后问题是在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处在同一行、同一列或同一斜线上,问满足这样的要求有多少种摆法。经过计算解出92种结果。
思路
如图所示的八皇后放置就可以满足题目中的要求,每一个皇后的同一行、用一列和同一斜线上都没有其它皇后。根据摆放的要求,可以假设当放置第一个皇后,可以在它所在的行、列和斜线上进行标记,说明该行、列和斜线已经被该皇后所占领,其它皇后不能被占有,下一个皇后只能处在第一个皇后不被占用的位置,以此类推。
分析
- 由图可看出,可以把上对角线的斜线分为15组,每一条斜线上的位置i-j所得的值都是一样的,每一条斜线都可以代表一个皇后所占领的位置,由于i-j的值有出现负数,可以把i-j所得的值再加上7,可得如下图
- 这时可以用一个flag1[15]数组去标记这些斜线上的位置是否被皇后所占领。
- 同理,也可以把下对角线的斜线分为15组,每一条斜线上的位置i+j所得的值都是一样的,故用另外一个flag2[15]数组去标记这些斜线上的位置是否被皇后所占领。
- 对于行和列的情况,可以用一个column[8]数组去标记皇后所对应的列是否被占领,因为每一行只能放置一个皇后,所有就不用对行进行标记是否被占领。
- 当摆放到第八个皇后时,说明已经摆放好这八个皇后的放置情况了,然后通过回溯继续找到另外一种的摆放的结果,直到没有其它摆放结果为止。
实现过程
全局变量
private static int[] queen = new int[8]; //八皇后的结果
private static boolean[] column = new boolean[8]; //列
private static boolean[] upperDiagonal = new boolean[15]; //上对角线
private static boolean[] lowerDiagonal = new boolean[15]; //下对角线
private static int count = 0; //记录结果数量
核心代码
public static void eightQueens(int i){
if (i>7){
//当放置完第8个皇后输出打印八个皇后放置情况
print();
}else{
for (int col = 0; col < 8; col++) {
//如果该所对应的列和斜线上没有被其它皇后标记占领
if (!column[col] && !upperDiagonal[i-col+7] && !lowerDiagonal[i+col]){
queen[i] = col; //将第i个皇后放置的列位置存放到数组中
column[col] = true; //标记该皇后所在的列被占领
//标记该皇后所在的斜线被占领
upperDiagonal[i-col+7] = true;
lowerDiagonal[i+col] = true;
eightQueens(i+1); //递归放置下一个皇后
//回溯
column[col] = false;
upperDiagonal[i-col+7] = false;
lowerDiagonal[i+col] = false;
}
}
}
}
打印输出八个皇后放置情况
private static void print() {
count++;
System.out.println("NO:"+count);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (queen[i]==j){
//1代表该位置放置的皇后
System.out.print("1 ");
}else {
//0代表该位置不放置
System.out.print("0 ");
}
}
System.out.println();
}
}
主函数
public static void main(String[] args) {
eightQueens(0);
}
输出结果(部分)
最后一共输出了92种八个皇后的放置情况,得出八个皇后问题的结果。