八皇后问题解法一(排列筛选法)

  • 本篇我们承接上一篇中的思想,想到了一个经典的算法题,八皇后问题:
  • 题目:在8*8的国际象棋上摆放8个皇后,使得其互相不能攻击,即任意两个换后不能在同一行,同一列,或者同一对角线上。如下图中所示,就是一个符合预期的摆放方式,问总共有多少中摆放方式。

  • 上图中的数字代表此处放置一个皇后,并且从上到下依次是0~7 总共8个。

  • 分析:

    • 由于8个皇后任意两个不能处在同一行,那么肯定每个皇后占据一行。
    • 有上图看,我们必然可以用数组来标识myQueen[8] 数组,数组中i 个数字表示位于第i 行的皇后
    • 例如以上图为案例可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能,
      • 就是我们直接用数组下标当成皇后所在的列
      • 用数组的下标对应的值当成皇后所在的行
    • 那么现在我们的思路就是求出 myQueen数组的全排列,接着在筛选出符合要求的
    • 符合要求的情况:
      • 我们依据以上思路得到的全排列,天然就不会再同一行,也不会在同一列
      • 只需要筛选左右对角线上是否有其他数据,那么只需要对比下标 i 和 j的差值与 i和j 下标对应的value的差值是否相等
      • i - j == myQueen[i] -myQueen[j] || j-i == myQueen[i] - myQueen[j]
      • 以上判断可以用具体案例来验证此处略。
  • 依据如上分析有如下代码:

/***  八皇后问题* @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {Integer[] eight = {0,1,2,3,4,5,6,7};getEightQueenPerMutain(eight, 0);List<Integer[]> realQueen = checkQueen(myQueen);for (Integer[] integers : realQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i]+",");}System.out.println();}}/*** 检查所有可能的八皇后排列,筛选出符合条件的:* i-j == integer[i] - integer[j] || j-i = integer[i]-integer[j] 情况的都是统一对角的* */public static List<Integer[]> checkQueen(List<Integer[]> myQueen){List<Integer[]> realEightQueen = new ArrayList<>();for (Integer[] integers : myQueen) {boolean isCheck = true;for (int i = 0; i < integers.length; i++) {if(!isCheck){break;}for (int j = i+1; j<integers.length;j++){if((i-j) == (integers[i] - integers[j])|| (j-i) == (integers[i] - integers[j])){isCheck = false;break;}}}if(isCheck){realEightQueen.add(integers);}}return realEightQueen;}/*** 八皇后问题排列解决方案* */public static void getEightQueenPerMutain(Integer[] eight, Integer start){if(eight == null || eight.length <= 1 || start == eight.length-1){Integer[] newEight = new Integer[eight.length];for (int i = 0; i < eight.length; i++) {newEight[i] = eight[i];}myQueen.add(newEight);}for (int i = start; i <= eight.length-1; i++) {Integer temp = eight[start];eight[start] = eight[i];eight[i] = temp;getEightQueenPerMutain(eight, start+1);temp = eight[start];eight[start] = eight[i];eight[i] = temp;}}
}

八皇后问题解法二(动态规划)

  • 接上文中,依然可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能

  • 那么上文中将所有排列列举出来后在对排列集合进行筛选得到最终的八皇后集合

  • 类似的思路,我们用穷举法将数组myQueen中包含0 ~ 7 的所有数字的可能一一列举,并且实时筛选,这样我们可以一个步骤直接得到想要的集合

  • 经过如上分析有如下代码:

/***  八皇后问题* @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {for (int i = 0; i < 8; i++) {Integer[] eight = new Integer[8];getEightQueen(eight, i);}for (Integer[] integers : myQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i] + ",");}System.out.println();}System.out.println(myQueen.size());}/*** 穷举+筛选* 直接获取八皇后问题最终结果* */public static void getEightQueen(Integer[] queen, int start){for (int i = 0; i < 8; i++) {queen[start] = i;if(checkout(queen, start)){if(start == queen.length -1){Integer[] realQueen = new Integer[8];for (int i1 = 0; i1 < queen.length; i1++) {realQueen[i1] = queen[i1];}myQueen.add(realQueen);}else {getEightQueen(queen, start + 1);}}}}/**
* 校验是否符合八皇后问题规则
*/public static boolean checkout(Integer[] queen, Integer end){Set<Integer> checkRepeat = new HashSet<>();for (int i = 0; i <= end; i++) {if(checkRepeat.contains(queen[i])){return false;}checkRepeat.add(queen[i]);for(int j = i+1; j<= end; j++){if(queen[i] == null || queen[j] == null){return false;}if((i-j) == (queen[i]- queen[j]) || (j-i) == (queen[i] - queen[j])){return false;}}}return true;}
}

八皇后问题解法三(回朔递归)

  • 依然可以用数组 myQueen[8] = {4,2,0,5,7,1,3,6} 来标识这种摆放的可能
  • 首先将第一个皇后放入第一列位置
  • 接着将第二个皇后分别放入第二三四等之后的位置,每次分别去检查放入的位置是否与之前的位置中放入的皇后是否在同一列,同一对角线
  • 接着依次对地三个,第四个,直到第八个皇后重复第二步骤,找出每个皇后所有合法的位置
  • 方法三 与方法二的实现方式非常类似,区别在于筛选,方法三种的筛选只需要对比最后一个元素与之前的元素是否冲突,在方法三中是每个皇后的位置依次检查,当进行到第5个皇后的时候,能保证前4个皇后的位置都是合法的,无需在检查之前的。
  • 具体实现方案如下,方法三实现方案更好理解。
/*** 八皇后问题** @author liaojiamin* @Date:Created in 15:03 2021/5/26*/
public class EightQueen {private static final List<Integer[]> myQueen = new ArrayList<>();public static void main(String[] args) {getEightQueenRetro();print();}public static void print() {for (Integer[] integers : myQueen) {for (int i = 0; i < integers.length; i++) {System.out.print(integers[i] + ",");}System.out.println();}System.out.println(myQueen.size());}/*** 回朔递归*/public static void getEightQueenRetro() {Integer[] eight = new Integer[8];check(eight, 0);}//递归回朔便利每一种可能public static void check(Integer[] eight, int n) {if (n == eight.length) {myQueen.add(Arrays.copyOf(eight, eight.length));return;}for (int i = 0; i < eight.length; i++) {eight[n] = i;if(judge(eight, n)){check(eight, n+1);}}}//筛选public static boolean judge(Integer[] eight, int n){for(int i=0;i<n;i++){if(eight[i] == eight[n] || Math.abs(n-i) == Math.abs(eight[n] - eight[i])){return false;}}return true;}
}

总结

  • 以上两个方法的整体思路类似,当题目需要我们按照一定规则摆放若干个数字的时候,我们可以先求出这些数字的所有可能,然后在一一判断每个组合是否满足题目给定的要求。
  • 方法一利用上一篇中的排列的算法得出所有排列可能,接着筛选,时间复杂度O( n3 )
  • 方法二 利用递归穷举方法得出所有数字的可能,并同时筛选,时间复杂度也是O(n3)
  • 两种算法的时间复杂度都并非很优,如有更好的算法思想,求在评论指出

上一篇:数据结构与算法–字符串的排列组合问题
下一篇:数据结构与算法-- 数组中出现次数超过一半的数字(时间复杂度的讨论)

数据结构与算法-- 八皇后问题(多种实现方案)相关推荐

  1. python深度优先算法 八皇后_八皇后问题——DFS(深度优先搜索)

    八皇后问题,是在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法? 算法思路: 八皇后问题实质为一种深度优先(DFS)搜索问题. ...

  2. 回溯算法(八皇后问题)

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...

  3. 分治回溯算法----八皇后问题

    八皇后问题:在一个8×8的棋盘中,放入8个皇后棋子,要求同行同列同斜线不能有重复的皇后棋子,八皇后问题一共有92种解法.如图所示:即八皇后问题的一个解. //分治回溯算法解决八皇后问题 public ...

  4. 学习笔记-回溯算法(八皇后问题)暴力法

    八皇后问题暴力解决法(介绍代码有说明) 先展示结果: 我这里用的是一维数组来展示的结果 array={7,3,0,2,5,1,6,4} 7的下标为0, 在这里下标+1表示的是第几个皇后也是行的位置,a ...

  5. 常考数据结构与算法:N皇后问题

    参考博客: https://blog.csdn.net/weixin_39651041/article/details/79972829 题目描述 NN皇后问题是指在N*NN∗N的棋盘上要摆NN个皇后 ...

  6. 数据结构:回溯--解决八皇后问题

    public class Queue8 {int max = 8;int count = 1;// 定义数组,保存皇后放置位置的结果,比如arr = {0,4,7,5,2,6,1,3}int[] ar ...

  7. Las Vegas算法八皇后问题最好的一种实现

    #include "pch.h" #include <iostream> #include <vector> #include <random> ...

  8. Java数据结构与算法(八)-二叉树

    一.为什么要使用树 有序数组插入.删除数据慢. 链表查找数据慢 树可以解决这两个问题 二.相关术语 树的结点:包含一个数据元素及若干指向子树的分支: 孩子结点:结点的子树的根称为该结点的孩子: 双亲结 ...

  9. 数据结构与算法-- 数组中出现次数超过一半的数字(时间复杂度的讨论)

    时间效率 互联网想对时间效率格外的敏感,所以我们总是在需求迭代一定程度后去做优化.而且我们解决问题的时候,时间效率往往是一个考查的重点.因此我们平时编码过程中就必须不断的优化效率,追求完美的态度与能力 ...

最新文章

  1. java取list中最大数值_Java后台通过Collections获取list集合中最大数,最小数代码
  2. 计算机安装两个键盘会怎样,外设门诊:一个键盘能否连接两个接收器?
  3. 四月读书主题整理——用尽费退,打磨身体
  4. Python·Jupyter Notebook各种使用方法
  5. android 播放MP3实例
  6. MarkDown的介绍
  7. LOFTERD18B542F16FF685FD684F427B4…
  8. Maven-打外部jar包
  9. c4dr20怎么安装oc渲染器怎么安装_c4d怎么安装oc渲染器/插件
  10. linux画图工具的下载,Drawing Linux(简单画图工具)最新版下载
  11. Linux Shell脚本面试25问
  12. VSCode沙绿色主题设置
  13. Pangu Separates Heaven and Earth(签到题)
  14. 给想上MIT的牛学生说几句
  15. npm install XXX 报错:error An unexpected error occurred:
  16. 点击右键计算机属性弹出任务管理器,win10查看内存条型号的步骤
  17. android百度网盘不限速,什么?百度网盘不限速?而且安卓和iOS都支持,开玩笑吧?...
  18. ADAS需要用到的技术
  19. 手游运营者必学:运营的核心、宗旨和目标
  20. JAVA读文件类之FileReader/InputStreamReader/BufferedReader

热门文章

  1. 递归和非递归实现规律函数
  2. Andorid之华为手机开发模式不打印日志
  3. Android之UI线程与子线程交互设计的5种方法
  4. php本地的调试安装,教你本地安装、运行、调试PHP程序
  5. 中国十大最美梯田,个个都美如画!
  6. 物理太难?这些虚拟动图,让你看懂物理
  7. 又来了!深度学习PyTorch与TensorFlow到底哪家强?
  8. 有一说一,确实。。 | 今日最佳
  9. 竞赛发布|100万奖金寻DT时代“最强大脑”!
  10. 从头到尾彻底理解傅里叶变换算法(上)