八皇后问题
八皇后问题:
八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。
7 | 皇后 | |||||||
---|---|---|---|---|---|---|---|---|
6 | 皇后 | |||||||
5 | 皇后 | |||||||
4 | 皇后 | |||||||
3 | 皇后 | |||||||
2 | 皇后 | |||||||
1 | 皇后 | |||||||
0 | 皇后 | |||||||
y /x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
下面我们来写代码
首先我们先创建一个成员变量用来记下成功的次数
创建一个长度为8的数组,其索引值为y,数组里存的值为x,用于记录皇后放的位置
public class EightQueen {
int count = 0;
int[] queen = new int[8];
}
皇后有点位置可以放。而有的位置不能放,所以我们就需要定义一个方法来判断皇后是否可以放置。
由于第一个皇后可以随意放,所以我们可以直接返回true
public boolean isPut(int x, int y) {
if(y == 0){
return true;
}
}
然后判断后续皇后所放置的位置,由于任意两个皇后都不能处于同一行、同一列或同一斜线上,所以
- 同一行:由于用数组索引记录的y值,所以不会出现在同一行的情况。
- 同一列: 就是所判断位置的x值与之前放置的皇后的x值是否相等。
- 同一斜线:可以使用斜率来进行判断,同一斜线上上的斜率为正负1,也就是(y1-y2)/ (x1-x2)=正负1;也就可以理解成(y1-y2)的绝对值与(x1-x2)的绝对值相等。
实例如下:
public boolean isPut(int x, int y) {
if(y == 0){
return true;
}
for (int i = 0; i < y; i++) {
if (Math.abs(y - i) == Math.abs(x - queen[i]) || x == queen[i]){
return false;
}
}
return true;
}
接着就到了我们的主体部分(这里我们使用递归来解决)
首先我们要先写好递归的出口,由于我们只需要放置8位皇后,所以我们可以使用数组queen的索引来进行计数,当其超过7时,则结束。此时我们的成功次数的计数器(count)加一,并通过Arrays.toString(queen)方法将8为皇后的位置打印出来。
public void eightQueen(int y) {
if (y > 7) {
count++;
System.out.println(Arrays.toString(queen));
return;
}
}
然后通过一个for循环,对同一行的每个位置都进行判断,如果可以放置,则将其x值赋给queen[y],并继续放置下一位皇后。
public void eightQueen(int y) {
if (y > 7) {
count++;
System.out.println(Arrays.toString(queen));
return;
}
for (int i = 0; i < 8; i++) {
if (isPut(i, y)) {
queen[y] = i;
eightQueen(y + 1);
}
}
}
程序写到这里基本上已经结束了,我们只需要在main方法中写上测试就可以运行了
下面是我整个程序的代码
import java.util.Arrays;
public class EightQueen {
//记录成功的次数
int count = 0;
//记录皇后放的位置,其索引值为y,数组里存的值为x
int[] queen = new int[8];
//判断皇后在(x,y)位置处是否可以放置
public boolean isPut(int x, int y) {
if (y == 0) {
return true;
}
for (int i = 0; i < y; i++) {
if (Math.abs(y - i) == Math.abs(x - queen[i]) || x == queen[i]) {
return false;
}
}
return true;
}
//通过递归判断皇后放置的位置
public void eightQueen(int y) {
if (y > 7) {
count++;
System.out.println(Arrays.toString(queen));
return;
}
for (int i = 0; i < 8; i++) {
if (isPut(i, y)) {
queen[y] = i;
eightQueen(y + 1);
}
}
}
public static void main(String[] args) {
EightQueen e = new EightQueen();
e.eightQueen(0);
System.out.println(e.count);
}
}
一共 92 种排法。代码还是很容易能够看的懂的。只要思路清晰,大家就可以一步步的实现代码。文中若有不对的地方,还请大神指点指点。