一、八皇后问题

  八皇后问题是一个以国际象棋为背景的问题:如何能够在8 × 8 的国际象棋棋盘上放置八个皇后Queen),使得任何一个皇后都无法直接吃掉其他的皇后。为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的N皇后摆放问题:这时棋盘的大小变为 N ×N,而皇后个数也变成 N当且仅当 n = 1 或 n ≥ 4 时问题有解。

二、利用回溯法递归求解N-皇后问题

  生成棋盘所有皇后摆放的可能配置,并打印满足给定约束的配置。回溯算法的思想是将皇后从最左边的列开始一一放置在不同的列中。 当我们将皇后放在一列中时,检查是否与已经放置的皇后发生冲突。 在当前列中,如果找到没有冲突的行,则将该行和列标记为解决方案的一部分。 如果由于冲突而找不到这样的行,那么我们将回溯并返回 false

  首先是从棋盘最左边的列开始摆放皇后。

算法主要内容:

1. 当 col = N 时,所有皇后摆放完毕,问题有解

2. 算法从每一列的每一行来推进问题的求解:

  • a) 如果该位置 (i, j) 能把皇后无冲突的放进去,标记这个位置为 1,然后一直递归求解下一列的某行位置能否求解问题;
  • b) 如果这个位置能摆放皇后则返回 true;
  • c) 如果放置皇后并不能解决问题,取消标记此 (i, j)(回溯),然后转到步骤(a)尝试其他行。

3. 如果所有列所有行都尝试探索过后依然无解,返回 false(回溯)。

三、N-皇后问题的实现

  检查当前位置放置皇后会与之前放置的皇后冲突。这里的时间复杂度为 O(N)。

 1     /**
2 * 用于检查是否可以将Queen放在当前位置上
3 *
4 * @param board
5 * @param row
6 * @param col
7 * @return
8 */
9 private boolean isSafe(int[][] board, int row, int col) {
10 int i, j;
11
12 /* 是否在同一行(左侧) */
13 for (i = 0; i < col; i++)
14 if (board[row][i] == 1)
15 return false;
16
17 /* 是否在反对角线方向上 */
18 for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
19 if (board[i][j] == 1)
20 return false;
21
22 /* 是否在对角线方向上 */
23 for (i = row, j = col; j >= 0 && i < N; i++, j--)
24 if (board[i][j] == 1)
25 return false;
26
27 return true;
28 }

  通过递归方式来探索问题的解,在所有位置尝试完之前,探索问题的解失败时通过回溯来寻找下一个皇后的摆放位置,回溯同时把摆放位置的标记复原。对于N皇后的时间复杂度,分析起来有点复杂,但从中可以分析其时间复杂度为 O(N3)。

 1     /**
2 * 递归求解N-Queen问题
3 *
4 * @param board
5 * @param col
6 * @return
7 */
8 private boolean solveNQUtils(int[][] board, int col) {
9 /* 如果所有皇后都被放置, 然后返回true */
10 if (col >= N)
11 return true;
12
13 /* 考虑当前col能否摆放Queen */
14 for (int i = 0; i < N; i++) {
15 /* 当前位置是否能摆放Queen */
16 if (isSafe(board, i, col)) {
17 board[i][col] = 1;
18
19 /* 再次摆放Queen, 如果成功直接返回true */
20 if (solveNQUtils(board, col + 1)) {
21 return true;
22 }
23
24 /* 这是在某列无法放Queen回溯时把queen移走 */
25 board[i][col] = 0;
26 }
27 }
28
29 return false;
30 }

本文源代码:

  1 package algorithm;
2
3 /**
4 * N皇后问题,回溯法,简单分析一下,时间复杂度大概为 O(N^3)
5 */
6 public class NQueenProblem {
7 private final int N = 8;
8
9 /**
10 * 打印符合条件的摆放棋盘
11 *
12 * @param board
13 */
14 private void printSolution(int[][] board) {
15 for (int i = 0; i < N; i++) {
16 for (int j = 0; j < N; j++) {
17 System.out.print(" " + board[i][j] + " ");
18 }
19 System.out.println();
20 }
21 }
22
23 /**
24 * 用于检查是否可以将Queen放在当前位置上
25 *
26 * @param board
27 * @param row
28 * @param col
29 * @return
30 */
31 private boolean isSafe(int[][] board, int row, int col) {
32 int i, j;
33
34 /* 是否在同一行(左侧) */
35 for (i = 0; i < col; i++)
36 if (board[row][i] == 1)
37 return false;
38
39 /* 是否在反对角线方向上 */
40 for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
41 if (board[i][j] == 1)
42 return false;
43
44 /* 是否在对角线方向上 */
45 for (i = row, j = col; j >= 0 && i < N; i++, j--)
46 if (board[i][j] == 1)
47 return false;
48
49 return true;
50 }
51
52 /**
53 * 递归求解N-Queen问题
54 *
55 * @param board
56 * @param col
57 * @return
58 */
59 private boolean solveNQUtils(int[][] board, int col) {
60 /* 如果所有皇后都被放置, 然后返回true */
61 if (col >= N)
62 return true;
63
64 /* 考虑当前col能否摆放Queen */
65 for (int i = 0; i < N; i++) {
66 /* 当前位置是否能摆放Queen */
67 if (isSafe(board, i, col)) {
68 board[i][col] = 1;
69
70 /* 再次摆放Queen, 如果成功直接返回true */
71 if (solveNQUtils(board, col + 1)) {
72 return true;
73 }
74
75 /* 这是在某列无法放Queen回溯时把queen移走 */
76 board[i][col] = 0;
77 }
78 }
79
80 return false;
81 }
82
83 /**
84 * 解决并打印N-Queen的问题
85 *
86 * @return
87 */
88 private boolean solveNQ() {
89 int[][] board = new int[N][N];
90
91 if (!solveNQUtils(board, 0)) {
92 System.out.println("Solution does not exist");
93 return false;
94 }
95
96 printSolution(board);
97 return true;
98 }
99
100 public static void main(String[] args) {
101 NQueenProblem queen = new NQueenProblem();
102 queen.solveNQ();
103 }
104 }

算法:N-皇后问题的更多相关文章

  1. 回溯算法————n皇后、素数串

    回溯就是算法是搜索算法中一种控制策略,是一个逐个试探的过程.在试探的过程中,如果遇到错误的选择,就会回到上一步继续选择下一种走法,一步一步的进行直到找到解或者证明无解为止. 如下是一个经典回溯问题n皇 ...

  2. 算法——八皇后问题(eight queen puzzle)之回溯法求解

    八皇后谜题是经典的一个问题,其解法一共有种! 其定义: 首先定义一个8*8的棋盘 我们有八个皇后在手里,目的是把八个都放在棋盘中 位于皇后的水平和垂直方向的棋格不能有其他皇后 位于皇后的斜对角线上的棋 ...

  3. [算法] N 皇后

    N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 一. 求解N皇后问题是算法中回溯法应用的一个经典案例 回溯算 ...

  4. JS算法之八皇后问题(回溯法)

    八皇后这个经典的算法网上有很多种思路,我学习了之后自己实现了一下,现在大概说说我的思路给大家参考一下,也算记录一下,以免以后自己忘了要重新想一遍. 八皇后问题 八皇后问题,是一个古老而著名的问题,是回 ...

  5. 回溯算法 - n 皇后问题

    (1)问题描述 在 n × n 格的棋盘上放置彼此不受攻击的 n 个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n 后问题等价于在 n × n 的棋盘上放置 n 个 ...

  6. 7, java数据结构和算法: 八皇后问题分析和实现 , 递归回溯

    什么是八皇后问题: 指的是,在一个8 * 8的棋盘中, 放置8个棋子, 保证这8个棋子相互之间, 不在同一行,同一列,同一斜线, 共有多少种摆法? 游戏连接: http://www.4399.com/ ...

  7. noj算法 8皇后打印 回溯法

    描述: 输出8皇后问题所有结果. 输入: 没有输入. 输出: 每个结果第一行是No n:的形式,n表示输出的是第几个结果:下面8行,每行8个字符,‘A’表示皇后,‘.’表示空格.不同的结果中,先输出第 ...

  8. 算法——n皇后问题

    n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案. 每一种解法包含一个明确的 n 皇后问题的棋 ...

  9. 洛谷 P1219 八皇后【经典DFS,温习搜索】

    P1219 八皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...

  10. 【学习总结】java数据结构和算法-第一章-内容介绍和授课方式

    总目录链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 几个经典算法面试题 算法和数据结构的重要性 几个经典算法面试题 字符串匹配 暴力法:慢 kmp算法:更 ...

随机推荐

  1. 343 day08File类、递归

    day08[File类.递归] 主要内容 File类 递归 教学目标 [ ] 能够说出File对象的创建方式 [ ] 能够说出File类获取名称的方法名称 [ ] 能够说出File类获取绝对路径的方法 ...

  2. php学习记录,使用script脚本

    echo "<script>alert()</script>"; 原来还能这么用,之前以为echo就是普通的用来打印 同时还可以在script标签下使用lo ...

  3. vscode中tab键无法触发emmet

    在用户自定义处加上一个设置"emmet.triggerExpansionOnTab":true

  4. Promise源码实现与测试

    const PENDING = 'pending', FULFILLED = 'fulfilled', REJECTED = 'rejected' class MyPromise { construc ...

  5. requests接口自动化-列表与字典参数化

    def server_ip(): # 配置文件,通过修改配置,在不同环境进行测试 # dev_ip='https://www.baidu.com/' # sit_ip='https://cn.bing ...

  6. kubeadm 如何将节点加入集群

    kubeadm join 使用 token 过期之后(24小时过期),如何加入集群 一.重启生成新token # 创建新token kubeadm token create # 查看是否存在有效的 t ...

  7. CF891C-Envy【可撤销并查集】

    正题 题目链接:https://www.luogu.com.cn/problem/CF891C 题目大意 \(n\)个点\(m\)条边的一张无向联通图,每次询问一个边集能否同时出现在同一棵最小生成树上 ...

  8. P4332-[SHOI2014]三叉神经树【LCT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4332 题目大意 给出\(n\)个点的一棵有根三叉树,保证每个点的儿子个数为\(3\)或者\(0\),每个叶子有一 ...

  9. P4199-万径人踪灭【FFT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4199 题目大意 给出一个只包含\(a,b\)的字符串 求有多少个不连续的回文子序列(字母回文,位置对称) \(1 ...

  10. Dapr + .NET Core实战(十-终篇)K8S运行Dapr

    工作原理 为了实现在k8s上安装Dapr,Dapr需要部署dapr-sidecar-injector.dapr-operator.dapr-placement和dapr-sentry服务. dapr- ...