n皇后问题-回溯法求解

1.算法描述

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

n皇后是由八皇后问题演变而来的。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

2.算法分析

随着计算机的普及和发展,以前人们无法解决的问题,计算机可以简单计算出来。而且思路十分清晰,那就是暴力求解,遍历所有情况,然后计算出解的个数。

2.1 回溯法

按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法

2.2 回溯法思路

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

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

其实并不需要一个n*n的数组,我们只需要一个n长度的数组来存位置。

表示方式: arr[i] = k; 表示: 第i行的第k个位置放一个皇后。这样一个arr[n]的数组就可以表示一个可行解, 由于回溯,我们就可以求所有解。

2.3 n皇后回溯求解

因为八皇后不能在同行,同列, 同斜线。

  1. 每一行放一个皇后,就解决了不在同行的问题。
  2. 在第i行的时候,遍历n列,试探位置。和之前所有行放的位置进行比较。
  3. 比较列:当前列col 不等于 之前 所有列。 即col != arr[i].
  4. 比较斜线, 因为不再同一斜率为1或者-1的斜线。(row - i) / (col - arr[i]) != 1 或 -1
    可以取巧用绝对值函数: abs(row-i) != abs(col-arr[i])

我们可以提取比较方法:

public boolean comp(int row, int col){   //当前行和列for (int i = 0; i < row; i++)  //比较之前row -1 列。{if(col == arr[i] || abs(row-i) != abs(col-arr[i]))  //如果在同一列,同一斜线return false;}return true;
}

比较函数写完后, 就只剩下回溯过程, 我们采用递归的方式回溯,比较好理解。

//当前层  row
for (int i = 0; i < n; i++){if(comp(row, i)){arr[row] = i;//同样方式遍历下一层。 row + 1}
}

2.4 时间复杂度

最坏的情况: 每一行有n种情况,有n行, 所以时间复杂度为O(n^n)。
但是由于回溯法会提前判断并抛弃一些情况,使得时间复杂度并没有想象中那么高。但是说是O(n!)也不太对,具体怎么算,暂时也不太清楚。(之前想当然了,此处有修正,多谢评论中的提醒。)

2.5 空间复杂度

因为只用了arr[n]的数组,也就是O(n).

3.代码实现

public class NQueen {private int n;private long count;private int[] arr;
//    private int nn;public NQueen(int n){this.n = n;//      nn = (1 << n) - 1;count = 0;arr = new int[n];}/*** row col   i  arr[i]* @param row* @param col* @return*/public boolean Check(int row, int col){for(int i = 0; i < row; i++){if(col == arr[i] || Math.abs(row - i) == Math.abs(col - arr[i])) //在同一列或者在同一斜线。一定不在同一行return false;}return true;}public void FindNQueen(int k) {if (k == n) {   //求出一种解, count+1count++;return;}for (int i = 0; i < n; i++) {if (Check(k, i)) {   //检查是否满足条件arr[k] = i;      //记录FindNQueen(k + 1);   //递归查找}}}public static void main(String args[]){NQueen nQueen = new NQueen(13);nQueen.FindNQueen(0);System.out.println(nQueen.count);}}

4. 拓展,位运算+回溯法实现

虽然计算机算的很快,但是上诉方法实在是太慢了, java就更慢了。如何网上就有大佬给出了位运算求解。精妙的不行。

4.1 算法思路

我们不再用数组来存储位置,而是用一个整数k,k一开始等于0. 不是普通的0.我们也不比较了,直接用两个整数l和r 记录在斜线在当前行不能走的位置。如果是n皇后, 那么用一个整数
nn = 1 << n 表示结束。

举个栗子吧: 8皇后问题。

初始化 那么我们就变成二进制的角度来看这些初始化的数据吧。

k = 00000000, l = 00000000, r = 00000000; nn = 11111111; (<- 8个0 8个1)

  1. k: 每个位置i的0表示没有皇后,1表示在第i个位置放了一个皇后。
  2. l: 0表示之前所有的列中放的皇后斜率为-1的线上没有涉及这个位置, 1 表示涉及到了,不能放皇后
  3. r: 同l, 所有斜率为1的线涉及的位置。

l和r的实现:

比如k = 00110001. 我要在第4个为位置放一个皇后, 假设l和r都没有涉及这个位置。

那么这个位置x= 00001000.

  1. k = (k & x) = 00111001.
  2. l = (l & x) << 1.
  3. r = (r & x) >> 1.

假设l = 00110001, r = 00100010.下一行,l表示斜率为-1不能放的位置, 那么第i+1行 l 中所有为1的数字都需要向左移动一位,r需要向右移动一位。 l & x 也就是加上当前选中的位置一起移动。

4.2代码实现

   //k  当前已走了多少个位置。   l 左斜线不能走的位置, r 右斜线不能走的位置。public void FindNQueen(int k, int l, int r){if(k == nn){count++;return;}int z = nn & (~(k | l | r));  //能走的位置, 和nn取并可以去掉前面多余的1while(z != 0){int index = z & (~z+1);   //最右边的一个1, 即要放皇后的位置。z -= index;   //去掉这个位置。FindNQueen(k | index, (l|index)<<1, (r|index)>>1);   //查找下一个。}}

4.3 算法分析

  1. 时间复杂度,应该同上分析一致,去掉但是少了检查的for循环,应该是O(n!)
  2. 空间复杂度,只用了几个变量, O(1).

5. 展望

其实还有其他方式和更快的方式求解,比如位运算+多线程, 还有号称时间复杂度为O(1),利用数学公式的构造法求解。扶我起来,我要继续学。

n皇后问题-回溯法求解相关推荐

  1. 回溯法求解N皇后问题(Java实现)

    回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并以此慢慢地扩大问题规模,迭代地逼近最终问题的解.这种迭代类似于穷举并且是试探性的,因为当目前的可 ...

  2. 回溯法求解N皇后问题及其时间复杂度分析

    回溯法求解N皇后问题及其时间复杂度分析 一.回溯法简介 1. 什么是回溯法? 2. 回溯法的时间复杂度分析 蒙特卡罗方法 蒙特卡罗方法在回溯法求解时间复杂度中的应用 二.回溯法求解N皇后问题 1. 回 ...

  3. 【算法分析】实验 4. 回溯法求解0-1背包等问题

    目录 实验内容 实验目的 实验结果 步骤1:描述与分析 步骤2:策略以及数据结构 步骤3 步骤4 步骤5 步骤6 实验总结 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设 ...

  4. java背包算法回溯法_【算法分析】实验 4. 回溯法求解0-1背包等问题

    [TOC] 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设计.算法描述.算法正确性证明.算法分析.算法实现与测试),通过回溯法的在实际问题求解实践中,加深理解其基本原理和 ...

  5. 拉斯维加斯算法结合回溯法求解n后问题

    实验8 拉斯维加斯算法结合回溯法求解n后问题 设stopVgas为采用拉斯维加斯算法随机排设的皇后个数,对n.stopVgas进行多组不同取值时,记录程序成功率.运行时间 ① 参考课件.教材.其它资料 ...

  6. n皇后问题(回溯法)

    目录 1.问题描述 2.问题分析 3.完整源码 1.问题描述 八皇后问题是十九世纪著名的数学家高斯于1850年提出的.问题是:在8×8的棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同 ...

  7. php生成迷宫图片,PHP实现基于回溯法求解迷宫问题的方法详解

    本文实例讲述了PHP实现基于回溯法求解迷宫问题的方法.分享给大家供大家参考,具体如下: 引言 最近在leetcode上看了些算法题,有些看着很简单的很常用的东西,竟然一下子想不出来怎么求解,比如说:实 ...

  8. 回溯法求解图着色问题

    回溯法求解图着色问题 #include <iostream> #include <cstdlib> using namespace std; #define n 5 #defi ...

  9. 算法设计与分析 实验三 回溯法求解地图填色问题

    回溯法求解地图填色问题 一.实验目的与要求 1.实验基本要求: 2.实验亮点: 二.实验内容与方法 三.实验步骤与过程 1.未优化的回溯: (1)算法描述: (2)编程实现 (3)运行并测试: 2.对 ...

最新文章

  1. 为什么要使用Go语言?Go语言的优势在哪里?
  2. 滑动窗口,拥塞控制算法
  3. Docker笔记:常用服务安装——Nginx、MySql、Redis(转载)
  4. Qt-VS开发:解决VS中使用带有信号槽的导出对象库时,信号槽不工作的问题
  5. android wear iphone7,iOS 10.1可修复iPhone7系列与Android Wear配对问题
  6. 从gbdt到xgboost
  7. 八.nginx网站服务实践应用
  8. 如何在虚拟机下安装一个Linux操作系统?(简简单单30步,安装Linux详细教程)
  9. 2008服务器系统c盘清理,WindowsServer2008清理C盘空间
  10. 考研数据结构之栈(2.5)——练习题之求解二次方根A的迭代函数,写出相应的递归算法和非递归算法(C表示)
  11. Word中如何删除某一页的页眉,不影响其他页眉
  12. J-LINK 软件下载地址
  13. css 拉伸 resize —— 实现可拉伸的div(含限制拉伸的尺寸)
  14. 怎么在ppt上设置文字滑动的效果html,PPT 中如何设置图片滚动切换效果
  15. wordpress友联_WordPress制作独立的友情链接(Links)页面
  16. html5 在线字体库,网络字体@font-face,如何处理网页中的特殊字体?
  17. linux 排程命令,linux 任务管理与调度
  18. 行业研究-全球与中国移动现场服务解决方案市场现状及未来发展趋势
  19. [leetcode] 116. Populating Next Right Pointers in Each Node @ python
  20. SAP、Oracle客户及实施商名单

热门文章

  1. 写在年初,回忆这些年的春节轨迹
  2. 崔毅东 C++程序设计入门(下) 第9单元:白公曾咏牡丹芳,一种鲜妍独“异常” 笔记
  3. 解决android studio 控制台乱码
  4. 【Cloudaily】蚂蚁金服与RISELab达成合作,Hadoop成新一波数据库攻击目标
  5. Docker镜像的优化
  6. npm 卡住 type-fest@^0.20.2 问题解决
  7. 神马VS百度,移动互联网战争全面升级!
  8. HCIE-Security Day46:AC准入控制Dot1x
  9. [电影笔记]电影世界:接纳平凡的自己
  10. 预测|2019软件测试职业发展趋势,附BAT、TMD入职指南!