实验名称

回溯法解N皇后问题

实验目的

  1. 掌握回溯递归算法、迭代算法的设计与实现;
  2. 设计回溯算法求解;
  3. 分析算法的时间复杂度。

实验环境

操作系统:win 10;

编程语言:Java;

开发工具:IDEA;

问题描述

n×n格的国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?

实验过程

回溯法

按照优先级条件向前搜索以达到目标。但是当探索到某一步时,发现原先选择并不能达到目标,就退回上一步重新选择,这种走不通就退回的技术叫做回溯。

问题解决思路

用数组模拟棋盘,从第一行开始,依次选择位置,如果当前位置满足条件,则向下选择位置,如果不满足条件,那么当前位置向后移动一位。

最后一个不满足,回溯到上一行,选择下一个位置继续进行探索。

其实并不需要一个n*n的数组,我们只需要一个长度为n的数组来存储位置,array[i] = k;表示第i行,第k个位置放皇后。

解题步骤

1. 因为皇后之间不能放在同一行,同一列,同一斜线。所以每行放一个皇后,就解决了不在同一行的问题。result[row]=j;表示第row行,第j列放置皇后。

2. 在第i行的时候,遍历n列,试探位置,和之前所有行放的位置进行比较。

3. 判断当前位置是否可以放皇后:如果当前列和之前皇后所在的列相等即result[i] == col 或者在同一个斜线上: result[i] == col - sub || result[i] == col + sub;代表当前位置不合法,返回false,如果当前位置可以放置皇后,那就将这个位置的坐标记录下来result[row] = j;j代表的是皇后所在的列;

4. 回溯,然后在下一行寻找皇后放置的位置。

代码实现

1.	package org.qianyan.algorithm;
2.
3. import java.util.ArrayList;
4. import java.util.Arrays;
5. import java.util.List;
6.
7. /**
8. * @Author Huhuitao
9. * @Date 2020/12/17 15:51
10. */
11. public class NQueens {
12. public static void main(String[] args) {
13. NQueens nQueens = new NQueens();
14. long begin_time = System.currentTimeMillis();
15. int N = 8;
16. List<List<String>> lists = nQueens.solveNQueens(N);
17. long end_time = System.currentTimeMillis();
18. System.out.println(end_time - begin_time + "ms");
19. lists.stream().forEach(list -> {
20. System.out.println("==========================");
21. for (int i = 0; i < list.size(); i++) {
22. System.out.println(list.get(i));
23. }
24. });
25. System.out.println("==========================");
26. System.out.println(N+"皇后,有"+lists.size()+"种解决方案");
27. }
28.
29. private List<List<String>> results = new ArrayList<>(); // 结果集
30.
31. public List<List<String>> solveNQueens(int n) {
32. int[] result = new int[n]; // 记录每一行皇后放置的 列坐标
33. backtracking(result, 0);
34. return results;
35. }
36.
37. /**
38. * 回溯
39. *
40. * @param result
41. * @param row
42. */
43. private void backtracking(int[] result, int row) {
44. if (row == result.length) {
45. //递归结束条件,放置完成最后一行,将结果添加到results
46. List<String> temp = new ArrayList<>();
47. for (int i = 0; i < result.length; i++) {
48. char[] str = new char[row];
49. Arrays.fill(str, '.');
50. str[result[i]] = 'Q';
51. temp.add(new String(str)); // 根据每一行出现皇后的位置填充解
52. }
53. results.add(temp); // 加入当前解
54.
55. }
56. for (int j = 0; j < result.length; j++) {
57. //如果这个位置能放置皇后
58. if (isValidation(result, row, j)) {
59. //记录放置坐标
60. result[row] = j;
61. //放置下一行
62. backtracking(result, row + 1);
63. }
64. }
65.
66. }
67.
68. // 验证,无同行/同列棋子
69. // 对角线无棋子
70. private boolean isValidation(int[] result, int row, int col) {
71. for (int i = 0; i < row; i++) { // 第一行可以放任意位置
72. int sub = row - i; // 行数差
73. // 如果同列、同对角线出现皇后,说明不能在row col放置皇后
74. if (result[i] == col || result[i] == col - sub || result[i] == col + sub) {
75. return false;
76. }
77. }
78. //检测结束后能放置
79. return true;
80. }

输出结果

算法分析

N 皇后问题的解空间是一棵n叉树,树的深度是n,最坏情况下解空间树深度是n,除了根节点和叶子结点,其余结点的子节点有n个分支,总分枝的个数是nn,每个分支都判断约束函数,判断约束条件需要O(n)的时间,因此耗时需要O(n(n+1)),所以时间复杂度是O(n^(n+1));

回溯法的另一个重要特性是在搜索执行的同时产生解空间,从开始结点起最长的路径是n,我们声明的result数组大小是n,用来保存皇后的坐标。所以该算法的空间复杂度是O(n)。

回溯法算是一种选优搜索法,按照选优条件深度优先搜索,达到目标,当搜索到某一步时,发现原先选择不是目标或者不是最优就退回重新选择。这种方法通过剪枝来减少递归的次数。如果超时的话可以换其他方法解决。

最新文章

  1. 可变字符串NSMutableString
  2. Android APK瘦身之Android Studio Lint (代码审查)
  3. iOS 简单动画 序列帧动画
  4. 基于Token的身份验证——JWT
  5. 标签简化Spring-MVC配置
  6. System.InvalidOperationException: Sequence contains no elements
  7. Android控件大全(三)——RecyclerView
  8. [geeksforgeeks] Count the number of occurrences in a sorted array
  9. epoll_create, epoll_ctl和epoll_wait
  10. 判断数组中有没有某个键 isset 和 array_key_exists 的效率比较
  11. 【转】Mac 下钥匙串不能授权访问怎么解决--不错
  12. Python 改变当前工作目录
  13. mysql create routine 权限的一些说明
  14. OCMOCM
  15. NYOJ 7-街区最短路径问题(曼哈顿距离)
  16. DropDownList如何绑定DataTable,如何绑定DataSet
  17. JDK1.8 ConcurrentHashMap源码阅读
  18. 如何通过dba_hist_active_sess_history分析数据库历史性能问题
  19. Java日志框架(Commons-logging,SLF4j,Log4j,Logback)
  20. 机器学习进阶-图像特征harris-角点检测 1.cv2.cornerHarris(进行角点检测)

热门文章

  1. 《深入理解计算机系统》实验二 —— Bomb Lab
  2. 2020 AC Saber夏季赛 游记
  3. springboot配置ssl证书
  4. logstash导入DNS解析数据到es中,中间有filebeat
  5. 小米k30 pro刷国际版rom
  6. css进阶 01-CSS中的非布局样式
  7. 图片放大缩小的zoom.js
  8. 用Python分析北京市蛋壳公寓租房数据
  9. 转载:从输入 URL 到页面加载完的过程中都发生了什么事情?
  10. 【译】理解Rust中的Futures(二)