韩顺平java P227
最近跟着老韩学java,学到P227集的时候老韩留了个八皇后问题,视频最后说以后会讲解这个问题,然后我找了一遍都没找到。这里给小伙伴分享一下我学习后的八皇后问题解法。
问题描述
老韩思路
思路解读
棋盘为八行八列,要放置八个皇后,且任意两个皇后都不能处于同一行、同一列或同一斜线。那就意味着每一行都要放置一个皇后。我们先在第一行放置皇后,再在第二行放置皇后,并且要检查与第一行的皇后是否冲突。如果不冲突,继续在第三行放置皇后,并且要分别检查是否与第一行和第二行的皇后冲突… …,直到在第八行放置皇后,并且要检查是否与前1-7行的皇后冲突。如果不冲突,则得到一种答案。
如何用arr[8]表示一种摆法
一维数组arr[8]共有8个元素,下标索引0、1、2、…、7分别表示棋盘的第1、2、3、…、8行。该索引对应的值表示棋盘对应的列。例如arr[0] = 0,表示第 1 个皇后放在棋盘的第 1 行的第 1 列;arr[1] = 4 表示第 2 个皇后放在棋盘的第 2 行的第列 5 列。所以图中的 arr[8] = {0, 4, 7, 5, 2, 6, 1, 3} 能表示一种摆法。
如何使用递归解决八皇后问题
使用递归解决该问题的关键:
1. 找到递归终止条件
我们从第 1 行开始放置皇后,每一行放置成功后,才能进行下一行的放置,如果我们成功的放置完八个皇后,我们就终止一次递归。
继续递归的条件:上一行放置成功。如代码段中的 judge 函数,上一行放置成功,judge返回true,继续迭代。
else中的for循环表示:index初始值为0,即第 1 行,遍历1 ~ 8列。如果放置成功,进入下一行(index+1),再次遍历1 ~ 8列。直至遍历完所有可能的结果。
if(index == 8) { // 退出条件:index能增加到8
// 可输出数组看看
for(int i = 0; i < 8; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
count++;
} else { // 递归
for(int i = 0; i < 8; i++) { // 8 列
arr[index] = i; // index行,i列
if(judge(index)) { // 如果该行皇后放置成功,则可以递归进入下一行进行放置,直至到达退出条件
check(index + 1);
}
}
}
2. 如何判断每一行是否放置成功
我们每行放置一个皇后,就已经避免了任意两个皇后在同一行,只需要用代码实现判断是否在同一列或同一条斜线。传入的参数 index 为当前正在放置的行,必须与前面的0 ~ index-1 行都不冲突。
- 在同一列时:
arr[index] == arr[i] - 在同一条斜线时:
Math.abs(index - i) == Math.abs(arr[index] - arr[i])
(相当于斜率为 1 或 -1)
代码如下:
// 判断该皇后是否与之前的皇后冲突
public boolean judge(int index) {
for(int i = 0; i < index; i++) {
if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
return false;
}
}
return true;
}
完整代码
由于老韩是在 方法的递归调用 中将的这个问题,所以我的代码承袭了老韩当时的风格,建了一个名为 T 的类。(手动狗头)
public class EightQueen {
public static void main(String[] args) {
int count = 0;
T t = new T();
count = t.check(0);
System.out.println("八皇后解法有:" + count + " 种");
}
}
class T {
int[] arr = new int[8];
int count = 0;
public int check(int index) { // 从0行开始
if(index == 8) { // 退出条件:index能增加到8
// 可输出数组看看
for(int i = 0; i < 8; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
count++;
} else { // 递归
for(int i = 0; i < 8; i++) { // 8 列
arr[index] = i; // index行,i列
if(judge(index)) { // 如果该行皇后放置成功,则可以递归进入下一行进行放置,直至到达退出条件
check(index + 1);
}
}
}
return count;
}
// 判断该皇后是否与之前的皇后冲突
public boolean judge(int index) {
for(int i = 0; i < index; i++) {
if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
return false;
}
}
return true;
}
}
public boolean judge(int index) {
for(int i = 0; i < index; i++) {
if(arr[index] == arr[i] || Math.abs(index - i) == Math.abs(arr[index] - arr[i])) {
return false;
}
}
return true;
}
有疑问欢迎评论区留言!
如果觉得我讲的不清楚,可参考以下链接:
https://www.bilibili.com/video/BV1Yf4y1Q7kJ