一文搞懂数据结构之 递归-八皇后问题
作者:互联网
八皇后是一个经典的递归问题,为了加深对八皇后解题思路的理解,故写此笔记
首先,了解一下八皇后问题:
八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。 问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
根据八皇后问题提取八皇后摆放条件
1. 任意皇后不能在同一列
2.任意皇后不能在同一行
3. 任意皇后不能在同一斜线
画图理解:
肉眼观察,在同一行,同一列的好判断,那么在同一斜线上的怎么判断呢,这里再来看一个图
可以看到,蓝皇后和绿皇后在同一斜线上,和红皇后也在同一斜线上,
通过观察,可以发现,蓝皇后到绿皇后的横向距离和纵向距离相等,都是3 ,而到红皇后的横纵距离也相等是1。不难发现,蓝皇后到到红绿皇后的横纵距离分别相等,而那条斜线,他的斜率是1 或-1,根据计算蓝皇后和每个皇后的斜率,只要不是1 或-1 再加上条件 不在同一行,同一列,我们就可以知道这个皇后的摆放位置是否符合规则。
总结条件:【1. 不在同一行 | 2. 不在同一列 | 3. 和已放置的皇后的斜率不等一 1 或 -1 即 绝对值不等一1 】
整个回溯求解过程中,最难理解的可能就是皇后的斜边冲突问题。
求解约定:
定义一个一维数组去作为棋盘
一维数组的下标是棋盘的行,一维数组的值表示皇后放在该行的第几列
假如 arr[0] = 0 下标是0 值是 0 就是棋盘的第1行,第一列,就是第1个黑皇后的位置
假如 arr[1] = 2 下标是1 值是 2 就是棋盘的第2行,第3列 ,就是第2个绿皇后的位置
假如 arr[3] = 6 下标是3 值是 6 就是棋盘的第4行,第7列 ,就是第4个红皇后的位置
.......
那么,判断第 n 和皇后位置摆放是否符合规则的条件就是
第 n 个皇后所在的列和已放置的皇后不在同一列, arr[i] != arr[n] i 取值 [0,n)
第 n 个皇后和已放置皇后的横向距离 != 纵向距离 即 (n-i) != | arr[n] - arr[i] |
(n-i) 是纵向距离,即隔了多少行,
而,arr[n] 是第n 个皇后所在的列,arr[i] 是第 i 个皇后所在的列
所以 | arr[n] - arr[i] | 即第n个皇后 和第 i 个皇后的列距离的绝对值
求解八皇后代码:注释很全
package pers.uxteam.data;
/*
* 约定: 用一个一维数组表示八皇后棋盘,
* 八皇后棋盘一共 8 行 8 列 范围是[0,7]
* 那么,一维数组的下表表示棋盘的行,
* 一维数组的值表示皇后所在的列 取值范围 [0,7]
* 例如 :int[] map = [4, 2, 0, 5, 7, 1, 3, 6]
* map[0] = 4 // 表示在棋盘的第 0 行,第 4 列 是第一个皇后的摆放位置
* map[1] = 2 // 表示在棋盘的第 1 行,第 2 列 是第一个皇后的摆放位置
* map[3] = 0 // 表示在棋盘的第 3 行,第 0 列 是第一个皇后的摆放位置
* .......
*
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0]
* */
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Queue8 {
private int max = 8; // 定义八行八列
private int[] chess = new int[max];
// 放置第 n 个皇后
public void layon(int n){
// 如果放到了第 max 个皇后,就结束迭代
if (n == max){
// 可以打印 chess 观察皇后摆放
show();
return;
}
// 放置 n 个皇后
for (int i = 0; i < max; i++){ // 这个循环的意义是,皇后放在第 i 列是否合适
chess[n] = i; // 放到这一列
if (isRight(n)){ // 检测放到这一列,皇位是否安稳
// 如果可以,就继续迭代,去放 下一个皇后 n + 1
layon(n+1);
}
// 否则继续循环,放置到其他列
}
}
// 判断第n个皇后的位置是否和其他皇后冲突
public boolean isRight(int n){
// 根据约定,我们知道,在摆放第 n 个皇后时,不能和其他皇后在同一列,
// 也就是数组的值不相同,这是第一个条件
// 每个皇后都不能在同一斜线上,也就是皇后到皇后之间的行和列距离不能相等,
// 不然就是正方形,,那么这条斜线的斜率要么是1,要么是-1 可以使用绝对值化,
// 判断行列距离是否相等。
// 和前面 的皇后比较是否冲突,当我们摆放 第 n 个皇后时,前面已经有了 n -1 个皇后
// 每个都要判断
for (int i = 0;i<n;i++){
if (chess[i] == chess[n] || Math.abs(n-i) == Math.abs(chess[n] - chess[i])){
// 冲突
return false;
}
}
return true;
}
public void show(){
int[][] chess = new int[max][max];
// 将一维数组恢复成二维数组打印
for (int i = 0; i< max; i++){
chess[i][this.chess[i]] = 1;
}
for (int[] row : chess){
// 打印每一行
List<Integer> collect = Arrays.stream(row).boxed().collect(Collectors.toList());
System.out.println(collect);
}
}
}
标签:arr,棋盘,递归,同一,int,摆放,皇后,搞懂,数据结构 来源: https://blog.csdn.net/jsupoker/article/details/119463700