一、问题介绍
八皇后问题,是一个古老而著名的问题,是回溯的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
二、解题思路
1) 第1个皇后先放(1,1)
2) 第2个皇后放在(2,1),然后判断是否OK[即判断是否合法], 如果不OK,继续放在(2,2)、(2,3)、……(2,N)找到一个合法的位置。
3) 按照步骤2)继续寻找第3个皇后、第4个皇后,……第8个皇后。若皇后x未找到合法位置,则回溯到皇后x-1,寻找皇后x-1的另一个合法的位置,再继续寻找皇后x、皇后x+1,……皇后N。
4) 当找到第8个皇后的合法位置时,则表明找到一个正解。
5) 可继续往后寻找,找到所有的方案
三、代码实现
1、说明
array[0]不使用,array[1]为第一个皇后的位置,array[2]为第一个皇后的位置……
public class QueenTest {
int N;//N皇后
int[] array = new int[N + 1];//N皇后的位置
int count = 0;//记录方案数量
//构造器
public QueenTest(int n) {
N = n;
}
//打印方案
void print(int[] array) {
count++;
System.out.print("方案" + count + ":");
for (int i = 1; i <= N; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
}
2、判断第i个皇后是否合法
说明:由于我们是按顺序依次,按行寻找皇后的位置的,不用判断皇后是否在同一行。只需判断两个皇后是否同一列或同一斜线上。同一斜线:即表明两皇后位置的斜率的绝对值为1
Boolean judge(int i) {
for (int j = 1; j < i; j++) {
if (array[j] == array[i] || Math.abs(i - j) == Math.abs(array[i] - array[j])) {
return false;
}
}
return true;
}
3、求解N皇后的方案1--非递归/回溯
说明:按照上面解题思路,写的代码
void queen() {
int i = 1;//放置第i个皇后
while (i >= 1 && i <= N) {
array[i]++;//寻找第i个皇后的位置
while (array[i] <= N && !judge(i)) {//判断第i个皇后的位置是否合法
array[i]++;
}
if (array[i] <= N) {//第i个皇后找到一个合法位置
if (i == N) {
print(array);//打印方案
} else {
i++;寻找下一个皇后的位置
}
} else {//第i个皇后找到一个合法位置
//回溯
array[i] = 0;
i--;
}
}
}
3、求解N皇后的方案2--递归
说明:传入的参数x为1!!!
void queen(int x) {//求解第x个皇后的位置,传入x=1
for (int i = 1; i <= N; i++) {
array[x] = i;//寻找第x个皇后的位置
if (judge(x)) {//判断合法性
if (x == N) {//递归退出的条件
print(array);
} else {
queen(x + 1);//求解第x+1个皇后的位置
}
}
}
}
4、测试代码main函数
说明:调用上面写的类方法
public static void main(String[] args) {
QueenTest queenTest = new QueenTest(8);
// queenTest.queen();
// System.out.println("一共有" + queenTest.count + "种方案");
queenTest.queen(1);
System.out.println("一共有" + queenTest.count + "种方案");
}